这是对上一个问题的评论的衍生:
Recheck Cond:
使用 PostgreSQL 9.4,在查询计划输出的位图索引扫描之后似乎总是有一行EXPLAIN
。
就像在EXPLAIN
引用问题的输出中一样:
-> Bitmap Heap Scan on table_three (cost=2446.92..19686.74 rows=8159 width=7) Recheck Cond: (("timestamp" > (now() - '30 days'::interval)) AND (client_id > 0)) -> BitmapAnd (cost=2446.92..2446.92 rows=8159 width=0) -> Bitmap Index Scan on table_one_timestamp_idx (cost=0.00..1040.00 rows=79941 width=0) Index Cond: ("timestamp" > (now() - '30 days'::interval)) -> Bitmap Index Scan on fki_table_three_client_id (cost=0.00..1406.05 rows=107978 width=0) Index Cond: (client_id > 0)
或者在EXPLAIN ANALYZE
一个简单的、巨大的表(很少work_mem
)的输出中:
EXPLAIN ANALYZE SELECT * FROM aa WHERE a BETWEEN 100000 AND 200000;
Bitmap Heap Scan on aa (cost=107.68..4818.05 rows=5000 width=4) (actual time=27.629..213.606 rows=100001 loops=1) Recheck Cond: ((a >= 100000) AND (a <= 200000)) Rows Removed by Index Recheck: 758222 Heap Blocks: exact=693 lossy=3732 -> Bitmap Index Scan on aai (cost=0.00..106.43 rows=5000 width=0) (actual time=27.265..27.265 rows=100001 loops=1) Index Cond: ((a >= 100000) AND (a <= 200000))
这是否意味着必须在位图索引扫描后再次检查索引条件?
我们还能从EXPLAIN
输出中学到什么?
正如@Chris 对引用问题的正确评论:
虽然这一切都是真的,核心开发人员 Heikki Linnakangas 是一流的资源,但这篇文章可以追溯到 2007 年(Postgres 8.2)。这是Michael Paquier 的一篇博客文章,其中详细解释了 Postgres 9.4,其中的输出
EXPLAIN ANALYZE
已通过更多信息得到改进。该
Recheck Cond:
行始终用于位图索引扫描。basic 的输出EXPLAIN
不会告诉我们更多信息。我们从EXPLAIN ANALYZE
问题的第二个引用中可以看到更多信息:在总共 4425 个数据页(块)中,有 693 个完全存储元组(包括元组指针),而其他 3732 个页在位图中是有损的(只是数据页)。当
work_mem
不足以存储从索引扫描构建的整个位图时,就会发生这种情况(无损)。对于有损共享中的页面,必须重新检查索引条件,因为位图只记住要获取的页面,而不是页面上的确切元组。并非页面上的所有元组都一定会通过索引条件,有必要实际重新检查条件。
这是pgsql 黑客上讨论新增内容的线程。作者Etsuro Fujita 提供了一个公式,用于计算最小值
work_mem
以避免有损位图条目和随后的条件重新检查。对于具有多个位图扫描的复杂情况,该计算不可靠,因此它不用于从EXPLAIN
. 它仍然可以作为简单案例的估计。附加线
BUFFERS:
此外,当使用
BUFFERS
option:运行时,EXPLAIN (ANALYZE, BUFFERS) ...
添加了另一行,如:这表明有多少基础表(和索引)是从缓存中读取的(
shared hit=279
)以及必须从磁盘中获取多少(read=79
)。如果您重复查询,对于不太大的查询,“读取”部分通常会消失,因为在第一次调用之后现在所有内容都被缓存了。第一个调用告诉您已经缓存了多少。随后的调用显示您的缓存可以处理多少(当前)。还有更多选择。关于
BUFFERS
选项的手册:继续阅读,还有更多。
这是源代码中的输出选项列表。
欧文,因为这是我们之前在评论线程中的讨论,所以我决定再深入一点......
我有一个来自合理大小的表的非常简单的查询。我通常有足够
work_mem
的,但在这种情况下,我使用了命令设置一个非常小的
work_mem
和让我的
work_mem
背对我的查询足够大。解释并重新检查条件
因此,仅使用
EXPLAIN
as运行我的查询我获得了低和高的结果
work_mem
:低的
work_mem
高的
work_mem
长话短说,
EXPLAIN
仅如预期的那样,查询计划表明可能有 Recheck 条件,但我们不知道是否会实际计算。解释分析和重新检查条件
当我们包含
ANALYZE
在查询中时,结果会告诉我们更多关于我们需要知道的内容。低的
work_mem
高的
work_mem
同样,正如预期的那样,包含
ANALYZE
向我们揭示了一些非常重要的信息。在低work_mem
情况下,我们看到索引重新检查删除了一些行,并且我们有lossy
堆块。结论?(或缺乏)
EXPLAIN
不幸的是,它本身似乎不足以知道是否真的需要重新检查索引,因为在位图堆扫描期间为了保留页面而删除了一些行 ID。使用
EXPLAIN ANALYZE
它可以很好地诊断中等长度查询的问题,但如果查询需要很长时间才能完成,那么运行EXPLAIN ANALYZE
以发现您的位图索引由于不足而转换为有损work_mem
仍然是一个困难的约束。我希望有一种方法可以EXPLAIN
从表统计信息中估计发生这种情况的可能性。