索引列上的非常慢的不同查询

Extremely slow distinct query on indexed column

在 Postgres 数据库中,我正在查询具有 3 亿行的大型 table 中 MY_DATE 的不同值。大约有 400 个,MY_DATE 列已编入索引。

Select distinct  MY_DATE from MY_TABLE;

查询 运行s 22 分钟

在我的 Oracle 数据库上使用完全相同的数据集和相同的索引定义进行相同的查询 运行s 11 秒。

查询计划显示查询正在使用索引:

EXPLAIN Select distinct  MY_DATE from MY_TABLE LIMIT 200;

给出:

QUERY PLAN
Limit  (cost=0.57..7171644.14 rows=200 width=8)
  ->  Unique  (cost=0.57..15419034.24 rows=430 width=8)
        ->  Index Only Scan using idx_obsdate on my_table  (cost=0.57..14672064.14 rows=298788038 width=8)

当我限制结果时,查询会变得更快。例如

Select distinct  MY_DATE from MY_TABLE LIMIT 5;

运行 亚秒。

但是:

Select distinct  MY_DATE from MY_TABLE LIMIT 50;

已经需要几分钟了。时间似乎随着 LIMIT 子句呈指数增长。

我希望 Postgres 查询在几秒钟内达到 运行,就像我的 OracleDB 一样。 索引扫描需要 20 分钟 - 即使是大的 table - 似乎也不合适。

对导致问题的原因以及我可以做什么有什么建议吗?

distinct values ... 300 million rows ... about 400 of them ... column ... indexed.

很多 更快的技术。模拟一个loose index scan(a.k.a。跳过扫描),并假设my_date被定义为NOT NULL(或者我们可以忽略NULL值):

WITH RECURSIVE cte AS (
   SELECT min(my_date) AS my_date
   FROM   my_table

   UNION ALL
   SELECT (SELECT my_date
           FROM   my_table 
           WHERE  my_date > cte.my_date
           ORDER  BY my_date
           LIMIT  1)
   FROM   cte
   WHERE  my_date IS NOT NULL
   )
TABLE  cte;

相关:

  • Optimize GROUP BY query to retrieve latest record per user

使用您提到的索引,它应该在 毫秒内完成

Oracle DB ... 11 seconds.

因为 Oracle 有本机索引跳过扫描而 Postgres 没有。在 Postgres 12 中有 ongoing efforts 实现类似的功能。

目前(Postgres 11),虽然使用索引效果很好,但即使在仅索引扫描中,Postgres 也无法向前跳过,必须顺序读取索引元组。如果没有LIMIT,则必须扫描完整的索引。因此我们在您的 EXPLAIN 输出中看到:

Index Only Scan ... rows=298788038

建议的新查询通过读取 400 个索引元组(每个不同值一个)实现相同的效果。 差别大

使用 LIMIT(没有 ORDER BY!),就像您测试的那样,一旦检索到足够的行,Postgres 就会停止。增加限制具有 线性 效果。但是,如果每个不同值的行数可以变化,那么增加的成本也会变化。