我有四张桌子; 两个用于当前数据,两个用于存档数据.其中一个归档表有数千万行.所有表都有几个窄索引,非常相似.
鉴于以下查询:
SELECT (SELECT COUNT(*) FROM A) UNION SELECT (SELECT COUNT(*) FROM B) UNION SELECT (SELECT COUNT(*) FROM C_LargeTable) UNION SELECT (SELECT COUNT(*) FROM D);
A,B和D执行索引扫描.C_LargeTable使用a seq scan
,查询大约需要20秒才能执行.表D也有数百万行,但只有C_LargeTable大小的10%左右
如果我然后修改我的查询以使用以下逻辑执行,这足以缩小计数,我仍然得到相同的结果,使用索引并且查询大约需要5秒,或1/4的时间
... SELECT (SELECT COUNT(*) FROM C_LargeTable WHERE idx_col < 'G') + (SELECT COUNT(*) FROM C_LargeTable WHERE idx_col BETWEEN 'G' AND 'Q') + (SELECT COUNT(*) FROM C_LargeTable WHERE idx_col > 'Q') ...
当存在完美良好的索引并且存在覆盖主键以确保唯一性时,对于计数具有全表扫描的I/O开销是没有意义的.我对postgres的理解是a PRIMARY KEY
不像SQL Server集群索引那样确定排序,但它隐式创建了一个btree索引来确保唯一性,我认为这应该比全表扫描要求的I/O少得多.
这可能是我在C_LargeTable中组织数据时可能需要执行的优化的指示吗?
主键上没有覆盖索引,因为PostgreSQL不支持它们(无论如何都是真实的,包括9.4).
由于MVCC可见性,因此需要堆扫描.索引不包含可见性信息.Pg可以进行索引扫描,但它仍然必须检查来自堆的可见性信息,并且索引扫描是随机I/O来读取整个表,因此seqscan将更快.
请确保您运行9.2或更新版本,并且自动清理被配置为运行频率在桌子上.然后,您应该能够在使用可见性图的位置进行仅索引扫描.这只适用于马注意到的有限情况; 在计数和仅索引扫描上查看维基页面.如果你不让autovacuum定期运行,可见性图将会过时,Pg将无法进行仅索引扫描.
将来,请确保您发布explain
或最好explain analyze
输出任何查询.