Postgresql - 由Index删除的行

时间:2014-10-17 05:58:02

标签: postgresql

有问题的表格在time

上有一个B树索引
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万行。

1 个答案:

答案 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