有问题的表格在time
testdb=> explain analyze select avg(gl) from cdstest where time between 1407700790 and 1407711590;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=1434716.75..1434716.76 rows=1 width=2) (actual time=20106.951..20106.952 rows=1 loops=1)
-> Bitmap Heap Scan on cdstest (cost=231261.49..1411280.42 rows=9374529 width=2) (actual time=811.495..10871.963 rows=9438824 loops=1)
Recheck Cond: (("time" >= 1407700790) AND ("time" <= 1407711590))
Rows Removed by Index Recheck: 204734
-> Bitmap Index Scan on timeindex (cost=0.00..228917.86 rows=9374529 width=0) (actual time=810.108..810.108 rows=9438824 loops=1)
Index Cond: (("time" >= 1407700790) AND ("time" <= 1407711590))
Total runtime: 20107.001 ms
(7 rows)
Rows Removed by Index Recheck: 204734
- 这是什么意思?这似乎是一个相当随意的数字。
给定时间范围之间的行数:
testdb=> select count(*) from cdstest where time between 1407700790 and 1407711590;
count
---------
9438824
(1 row)
该表包含约6,000万行。
答案 0 :(得分:10)
内部Bitmap Index Scan
节点正在生成一个位图,将1
放到找到与您的搜索关键字匹配的记录的所有位置,否则放置0
。由于您的表非常大,位图的大小越来越大,因此通过work_mem
配置的这类操作的可用内存变小,以保持整个位图。
当缺少内存时,内部节点将开始生成1
而不是记录,而是针对已知包含匹配记录的块。这意味着,外部节点Bitmap Heap Scan
必须从此块中读取所有记录并重新检查它们。很明显,会有一些不匹配的,他们的数字是你所看到的Rows Removed by Index Recheck
。
在即将推出的9.4中,会添加一项新功能,报告exact
节点返回的lossy
和/或Bitmap Index Scan
页面的数量。 lossy
是您想要避免的。您可以查看有关此here的更多信息。
最后,请参阅您的work_mem
设置并尝试增加它,仅适用于此特定会话。
我认为,增加约40%就足够了。
修改强>
我在这里跑了9.4beta3,所以我准备了一个小型展示柜:
DROP TABLE IF EXISTS tab;
SELECT id, id%10 mod
INTO tab
FROM generate_series(1,(1e7)::int) id;
CREATE INDEX i_tab_mod ON tab(mod);
VACUUM ANALYZE tab;
现在,我将work_mem
设置为最小可能值并检查它:
SET work_mem TO '64kB';
EXPLAIN (analyze, buffers)
SELECT * FROM tab WHERE mod=5;
EXPLAIN
提供以下两行:
Rows Removed by Index Recheck: 8896308
Heap Blocks: exact=510 lossy=43738
...
Execution time: 1356.938 ms
这意味着,64kB
可以容纳510个确切的块。所以我在这里计算总内存需求:
new_mem_in_bytes = (work_mem_in_bytes / exact) * lossy
= (( 64.0 * 1024 / 510 ) * 43738) / 1024
= 5488.7kB
事实上,这不是计算所需内存的精确方法,但我认为它足以满足我们的需求。所以我尝试了SET work_mem TO '5MB'
:
Heap Blocks: exact=44248
...
Execution time: 283.466 ms