Mar*_*eth 7 postgresql index explain postgresql-9.3
TL;DR:当“EXPLAIN (BUFFERS)”显示“索引扫描”时,它不会显示需要从索引中读取的页数。它只是省略了那个数字,还是它实际上不读取页面(我误解了索引的工作原理)?
我们有一个大的只读表,看起来像这样:
database=> \d my_table
Table "my_table"
Column | Type | Modifiers
-----------------------+------------------+-----------
id | integer |
date | date |
country_id | smallint |
...other columns...
Indexes:
"my_table_id_date_idx" btree (id, date)
Run Code Online (Sandbox Code Playgroud)
并且对该表的典型查询具有这样的 EXPLAIN...
database=> EXPLAIN (BUFFERS, ANALYZE) SELECT id, date, country_id FROM my_table WHERE id = 50 AND date BETWEEN '2015-04-01' AND '2015-04-07';
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on my_table (cost=448.40..70400.85 rows=18810 width=10) (actual time=9.011..1447.817 rows=10224 loops=1)
Recheck Cond: ((id = 50) AND (date >= '2015-04-01'::date) AND (date <= '2015-04-07'::date))
Buffers: shared hit=232 read=9994
-> Bitmap Index Scan on my_table_id_date_idx (cost=0.00..443.69 rows=18810 width=0) (actual time=6.467..6.467 rows=10224 loops=1)
Index Cond: ((id = 50) AND (date >= '2015-04-01'::date) AND (date <= '2015-04-07'::date))
Buffers: shared hit=2 read=30
Total runtime: 1450.175 ms
(7 rows)
Run Code Online (Sandbox Code Playgroud)
这是我如何分析这个:
我们最近在其索引上将此(只读)表更改为 CLUSTER,这大大减少了需要读取的页面。现在解释看起来像这样......
database=> EXPLAIN (BUFFERS, ANALYZE) SELECT id, date, country_id FROM my_table WHERE id = 50 AND date BETWEEN '2015-04-01' AND '2015-04-07';
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using my_table_id_date_idx on my_table (cost=0.57..36703.31 rows=20594 width=10) (actual time=0.029..4.830 rows=10224 loops=1)
Index Cond: ((id = 50) AND (date >= '2015-04-01'::date) AND (date <= '2015-04-07'::date))
Buffers: shared hit=160
Total runtime: 6.658 ms
(4 rows)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,它正在执行索引扫描。据我所知,索引扫描和位图索引/堆扫描之间的区别在于,前者将按照索引定义的顺序读取页面,而后者将创建要读取的页面位图(可能来自多个索引) ),对结果进行排序,并按顺序阅读。在我看来,在这两种情况下,都需要读取索引页才能实际确定要读取的结果数据页。
但是,在“索引扫描”中,“缓冲区”行有 160 页,根据我的其他测试,这是实际数据的页数,不包括我在上面的位图索引扫描中看到的 32 页索引本身。
database=> set enable_indexscan to false;
SET
database=> EXPLAIN (BUFFERS, ANALYZE) SELECT id, date, country_id FROM my_table WHERE id = 50 AND date BETWEEN '2015-04-01' AND '2015-04-07';
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on my_table (cost=491.14..76781.03 rows=20594 width=10) (actual time=1.003..3.873 rows=10224 loops=1)
Recheck Cond: ((id = 50) AND (date >= '2015-04-01'::date) AND (date <= '2015-04-07'::date))
Buffers: shared hit=160
-> Bitmap Index Scan on my_table_id_date_idx (cost=0.00..486.00 rows=20594 width=0) (actual time=0.981..0.981 rows=10224 loops=1)
Index Cond: ((id = 50) AND (date >= '2015-04-01'::date) AND (date <= '2015-04-07'::date))
Buffers: shared hit=32
Total runtime: 5.595 ms
(7 rows)
Run Code Online (Sandbox Code Playgroud)
这是否意味着索引扫描实际上并未从索引中读取?那么它如何知道要阅读哪些页面呢?索引扫描解释输出中是否省略了刚刚读取的索引页数?或者我对位图索引扫描中的那个值代表什么的理解是不正确的。
在这种情况下,它正在执行索引扫描。据我所知,索引扫描和位图索引/堆扫描之间的区别在于,前者将按照索引定义的顺序读取页面,而后者将创建要读取的页面位图(可能来自多个索引) ),对结果进行排序,并按 [heap] 顺序读取它们。
正确的。
还有仅索引扫描,其中读取索引以直接满足查询,并且对于读取的大多数索引页没有堆提取。如果系统不能确保页面对所有事务都可见,则仍然需要堆提取,因此它就像带有快捷方式的索引扫描。
在我看来,在这两种情况下,都需要读取索引页才能实际确定要读取的结果数据页。
正确的。
但是,在“索引扫描”中,“缓冲区”行有 160 页,根据我的其他测试,这是实际数据的页数,不包括我在上面的位图索引扫描中看到的 32 页索引本身。
我认为这是误解。该行将是从索引和堆读取的页面总和。不是所有的索引页,也不是所有的堆页,都需要被读取。
另一个重要的注意事项是“缓冲区”指标,就像 EXPLAIN 中的其他指标一样,是累积的:在父节点中读取的页数包括子节点的页数。因此,命中的 160 个缓冲区包括索引读取。实际上,在最后两种情况下,仅从堆中读取了 128 页。
归档时间: |
|
查看次数: |
580 次 |
最近记录: |