【发布时间】:2015-09-13 09:23:48
【问题描述】:
在我们的数据库中,我们有一个表 menus 有 515502 行。它有一列status,其类型为smallint。
目前,对于具有 status 和 3 的一组文档,一个简单的计数查询需要 700 毫秒。
explain analyze select count(id) from menus where status = 2;
Aggregate (cost=72973.71..72973.72 rows=1 width=4) (actual time=692.564..692.565 rows=1 loops=1)
-> Bitmap Heap Scan on menus (cost=2510.63..72638.80 rows=133962 width=4) (actual time=28.179..623.077 rows=135429 loops=1)
Recheck Cond: (status = 2)
Rows Removed by Index Recheck: 199654
-> Bitmap Index Scan on menus_status (cost=0.00..2477.14 rows=133962 width=0) (actual time=26.211..26.211 rows=135429 loops=1)
Index Cond: (status = 2)
Total runtime: 692.705 ms
(7 rows)
某些行的列值为 1,查询运行速度非常快。
explain analyze select count(id) from menus where status = 4;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=7198.73..7198.74 rows=1 width=4) (actual time=24.926..24.926 rows=1 loops=1)
-> Bitmap Heap Scan on menus (cost=40.53..7193.53 rows=2079 width=4) (actual time=1.461..23.418 rows=2220 loops=1)
Recheck Cond: (status = 4)
-> Bitmap Index Scan on menus_status (cost=0.00..40.02 rows=2079 width=0) (actual time=0.858..0.858 rows=2220 loops=1)
Index Cond: (status = 4)
Total runtime: 25.089 ms
(6 rows)
我观察到最通用的btree 索引是基于简单等式查询的最佳索引策略。 gin 和 hash 都比 btree 慢。
对于使用索引的任何过滤器更快地进行count 查询的任何提示?
我知道这是一个初学者级别的问题,所以对于我可能犯的任何错误,请提前道歉。
【问题讨论】:
-
如果你有一张大表并且索引使用率很好,你可以尝试优化过程。我的意思是:状态会经常变化吗?你能准备一张准备好总和的表格,并用触发器或函数来维护它吗?
-
id是这个表的主键吗?你可以试试count(*)吗? -
好的,所以如果查询和索引合适,您应该能够从仅索引扫描(自 9.2 起)中受益,这是我想知道版本的主要原因。
-
@user2512324
count(status)也应该可以工作。count(id)没有的原因是 PostgreSQL 没有通过证明id是NOT NULL来优化count(id)以等效于count(1),所以它认为它必须获取id字段,它不是索引的一部分,因此无法使用仅索引扫描获取。 -
如果您需要超快的速度,您可能需要考虑使用触发器或定期刷新的触发器来维护物化视图。请注意,触发器维护的 mat 视图往往会影响插入/更新/删除的并发性,并且定期更新的 mat 视图不会完全准确。
标签: sql postgresql indexing