postgres没有在SELECT COUNT(*)上使用索引来表示大型表

 百变精灵_tb 发布于 2023-02-12 19:03

我有四张桌子; 两个用于当前数据,两个用于存档数据.其中一个归档表有数千万行.所有表都有几个窄索引,非常相似.

鉴于以下查询:

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中组织数据时可能需要执行的优化的指示吗?

1 个回答
  • 主键上没有覆盖索引,因为PostgreSQL不支持它们(无论如何都是真实的,包括9.4).

    由于MVCC可见性,因此需要堆扫描.索引不包含可见性信息.Pg可以进行索引扫描,但它仍然必须检查来自堆的可见性信息,并且索引扫描是随机I/O来读取整个表,因此seqscan将更快.

    请确保您运行9.2或更新版本,并且自动清理被配置为运行频率在桌子上.然后,您应该能够在使用可见性图的位置进行仅索引扫描.这只适用于马注意到的有限情况; 在计数和仅索引扫描上查看维基页面.如果你不让autovacuum定期运行,可见性图将会过时,Pg将无法进行仅索引扫描.

    将来,请确保您发布explain或最好explain analyze输出任何查询.

    2023-02-12 19:05 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有