我有四张 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 或更新版本,并且 autovacuum是configured to run frequently在 table 上。然后,您应该能够在使用可见性 map 的地方进行仅索引扫描。正如 Horse 所说,这仅在有限的情况下有效;见the wiki page on count和 index-only scans .如果您没有让 autovacuum 足够定期地运行 visibility map将过时并且 Pg 将无法进行仅索引扫描。
在未来,确保你发布 explain
或最好是 explain analyze
输出与任何查询。
关于performance - postgres 不在 SELECT COUNT(*) 上为大表使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20386719/