tom*_*zer 4 sql postgresql indexing distinct query-optimization
在Postgres数据库中,我正在查询MY_DATE具有3亿行的大型表中的不同值。它们大约有400个,并且该列MY_DATE已建立索引。
Select distinct MY_DATE from MY_TABLE;
Run Code Online (Sandbox Code Playgroud)
查询运行22分钟。
在Oracle数据库上具有完全相同的数据集和相同的索引定义的相同查询运行11秒。
查询计划显示查询正在使用索引:
EXPLAIN Select distinct MY_DATE from MY_TABLE LIMIT 200;
Run Code Online (Sandbox Code Playgroud)
给出:
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)
Run Code Online (Sandbox Code Playgroud)
当我限制结果时,查询会变得更快。例如
Select distinct MY_DATE from MY_TABLE LIMIT 5;
Run Code Online (Sandbox Code Playgroud)
在不到几秒的时间内运行。
但:
Select distinct MY_DATE from MY_TABLE LIMIT 50;
Run Code Online (Sandbox Code Playgroud)
已经花了几分钟。该LIMIT子句的时间似乎成倍增加。
我希望Postgres查询能够像OracleDB一样在几秒钟内运行。索引扫描(即使是一张大桌子)也需要20分钟才能完成。
有什么建议导致问题的原因以及我该怎么办?
不同的值... 3亿行...其中约400 ...列...索引。
有很多更快的技术可以做到这一点。模拟一个松散的索引扫描(也称为跳过扫描),并假设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;
Run Code Online (Sandbox Code Playgroud)
有关:
使用您提到的索引应该以毫秒为单位完成。
Oracle DB ... 11秒。
因为Oracle具有本机索引跳过扫描,而Postgres没有。正在不断努力在Postgres 12中实现类似的功能。
目前(Postgres 11),虽然索引使用效果良好,即使在仅索引扫描中,Postgres也无法跳过,而必须按顺序读取索引元组。如果不使用LIMIT,则必须扫描完整的索引。因此,我们在您的EXPLAIN输出中看到:
仅索引扫描... 行= 298788038
建议的新查询通过读取400个索引元组(每个不同的值一个)实现相同的目的。很大的不同。
随着LIMIT(没有ORDER BY像你这样的测试!),Postgres的只要够检索行停止。增加限制具有线性作用。但是,如果每个不同值的行数可以变化,那么增加的成本也将变化。
| 归档时间: |
|
| 查看次数: |
113 次 |
| 最近记录: |