performance - postgres 不在 SELECT COUNT(*) 上为大表使用索引

标签 performance postgresql indexing sql-execution-plan

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

给出以下查询:

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 使用 seq 扫描,查询大约需要 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 的理解是 PRIMARY KEY 不像 SQL Server 集群索引,因为它确定排序,但它隐式创建 btree 索引以确保唯一性,我认为这应该需要更少I/O不如全表扫描。

这是否可能表明我可能需要执行优化以在 C_LargeTable 中组织数据?

最佳答案

主键上没有覆盖索引,因为 PostgreSQL 不支持它们(无论如何包括 9.4 在内)。

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

确保运行 9.2 或更新版本,并且 autovacuumconfigured to run frequently在 table 上。然后,您应该能够在使用可见性 map 的地方进行仅索引扫描。正如 Horse 所说,这仅在有限的情况下有效;见the wiki page on countindex-only scans .如果您没有让 autovacuum 足够定期地运行 visibility map将过时并且 Pg 将无法进行仅索引扫描。

在未来,确保你发布 explain 或最好是 explain analyze 输出与任何查询。

关于performance - postgres 不在 SELECT COUNT(*) 上为大表使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20386719/

相关文章:

node.js - 使用 Node.js 将数据加载到 Redshift

python - PostGIS 中多边形内的点

MYSQL 在简单查询中使用 ORDER BY 索引列时使用文件排序

.net - WCF的内部限制是什么

.net - 测量触发的事件数量?

android - 处理 Android 屏幕方向

mysql - 优化子查询和排序

JavaScript if 语句优化

ruby-on-rails - 检测 PostgreSQL json 字段的变化

sql - MariaDB是否支持重命名索引?