在Postgres数据库中,我正在查询具有3亿行的大型表中MY_DATE
的不同值。其中大约有400个,并且对列MY_DATE
进行了索引。
Select distinct MY_DATE from MY_TABLE;
查询运行 22分钟。
在Oracle数据库上具有完全相同的数据集和相同的索引定义的相同查询运行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分钟的时间。
有什么建议可以引起问题,我该怎么办?
答案 0 :(得分:4)
不同的值... 3亿行...其中约400行...列...已建立索引。
有很多 更快的技术可以做到这一点。模拟loose index scan(也称为跳过扫描),并假设已定义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;
相关:
使用您提到的索引应在毫秒内完成。
Oracle DB ... 11秒。
因为Oracle具有本机索引跳过扫描,而Postgres没有。在Postgres 12中有ongoing efforts个实现类似功能的工具。
当前(Postgres 11),尽管索引使用效果良好,即使在仅索引扫描中,Postgres也无法跳过,而必须按顺序读取索引元组。如果没有LIMIT
,则必须扫描完整的索引。因此,我们在您的EXPLAIN
输出中看到了
Index Only Scan ... rows=298788038
建议的新查询通过读取400个索引元组(每个不同的值一个)达到相同的目的。 大差异。
使用您测试过的LIMIT
(并且没有ORDER BY
!),只要检索到足够的行,Postgres就会停止。增加限制会产生 linear 效果。但是,如果每个不同值的行数可以变化,那么增加的成本也将变化。