【发布时间】:2013-12-21 14:37:55
【问题描述】:
我有四张桌子;两个用于当前数据,两个用于存档数据。其中一个存档表有数千万行。所有表都有几个窄索引并且非常相似。
鉴于以下查询:
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 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 的理解是,PRIMARY KEY 不像 SQL Server 集群索引,因为它确定了排序,但它隐式创建了一个 btree 索引以确保唯一性,我认为这需要的 I/O 比完整的要少得多表扫描。
这是否可能表明我可能需要执行优化以在 C_LargeTable 中组织数据?
【问题讨论】:
-
您使用的是哪个版本的 Postgres?只有 9.2 及更高版本才能使用索引。这也是一个常见问题解答:wiki.postgresql.org/wiki/…
-
我正在运行 9.3。您的回复解释了为什么会发生这种情况。有没有建议让它做其他事情?我尝试设置 enable_seqcan=false,但它似乎并没有产生太大的性能差异(后来我将其设置回 true)。
-
EXPLAIN ANALYZE查询的输出有和没有enable_seqscan = false请。另外,在桌子上运行VACUUM ANALYZE后它会改变吗?请始终在您的问题中包含SELECT version(),并查看stackoverflow.com/tags/postgresql/info 以获得更好问题的指导。 -
感谢您对我的耐心。我执行了 VACUUM ANALYZE C_LargeTable。 EXPLAIN ANALYZE 结果将归档表 D 更改为现在也执行 seq 扫描。然后我执行
VACUUM ANALYZE D并再次执行查询并返回到Index Only Scan
标签: performance postgresql indexing sql-execution-plan