在PostgreSQL中,我在tickets
表的日期字段上有一个索引。
当我将字段与now()
进行比较时,查询非常有效:
# explain analyze select count(1) as count from tickets where updated_at > now();
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=90.64..90.66 rows=1 width=0) (actual time=33.238..33.238 rows=1 loops=1)
-> Index Scan using tickets_updated_at_idx on tickets (cost=0.01..90.27 rows=74 width=0) (actual time=0.016..29.318 rows=40250 loops=1)
Index Cond: (updated_at > now())
Total runtime: 33.271 ms
如果我尝试将其与now()
减去间隔进行比较,它会下坡并使用位图堆扫描。
# explain analyze select count(1) as count from tickets where updated_at > (now() - '24 hours'::interval);
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=180450.15..180450.17 rows=1 width=0) (actual time=543.898..543.898 rows=1 loops=1)
-> Bitmap Heap Scan on tickets (cost=21296.43..175963.31 rows=897368 width=0) (actual time=251.700..457.916 rows=924373 loops=1)
Recheck Cond: (updated_at > (now() - '24:00:00'::interval))
-> Bitmap Index Scan on tickets_updated_at_idx (cost=0.00..20847.74 rows=897368 width=0) (actual time=238.799..238.799 rows=924699 loops=1)
Index Cond: (updated_at > (now() - '24:00:00'::interval))
Total runtime: 543.952 ms
使用日期算法查询是否有更有效的方法?
答案 0 :(得分:3)
第一个查询预计会找到 rows=74
,但实际上会找到rows=40250
。
第二个查询期望找到 rows=897368
并实际找到rows=924699
。
当然,处理23 x尽可能多的行需要相当多的时间。所以你的实际时间并不令人惊讶。
updated_at > now()
数据的统计信息已过时。运行:
ANALYZE tickets;
并重复您的查询。您认真地拥有updated_at > now()
的数据?这听起来不对。
ANALYZE
。
同时测试(仅在您的会话中):
SET enable_bitmapscan = off;
并重复第二个查询以查看没有位图索引扫描的时间。
普通的索引扫描按顺序从堆中获取行,如索引中所示。这简单,愚蠢,没有开销。快几行,但最终可能比行数越来越多的位图索引扫描更贵。
位图索引扫描在查找表之前从索引中收集行。如果多个行驻留在同一数据页面上,则可以节省重复访问次数并使事情变得更快。行越多,机会越大,位图索引扫描将节省时间。
对于更多行(约占表格的5%,严重依赖于实际数据),计划程序切换到表格的顺序扫描,并且根本不使用索引
最佳将是 index only scan ,与Postgres 9.2一起推出。只有满足一些先决条件才有可能。如果索引中包含所有相关列,则索引类型支持它,可见性映射表示数据页上的所有行对所有事务都可见,该页面不必从堆中获取(表并且索引中的信息就足够了。
决定取决于您的统计信息(Postgres希望查找的行数及其分布)以及cost settings,最重要的是random_page_cost
,cpu_index_tuple_cost
和effective_cache_size
。< / p>