在实际SQL优化工作中,我们经常会发现SQL 执行计划明明是 “Index Only Scan”,但执行计划后面却有 “Heap Fetches: x” ,也就是说实际执行计划还是访问了表记录。这是为什么了?

一、举个例子

1、创建数据

create table t1(id1 integer,id2 integer,name text);
insert into t1 select generate_series(1,100),generate_series(1,100),repeat('a',1000);
create index ind_t1 on t1(id1,id2);

2、查看执行计划

test=# explain analyze select id2 from t1 where id1=1;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Index Only Scan using ind_t1 on t1 (cost=0.14..8.16 rows=1 width=4) (actual time=0.024..0.025 rows=1 loops=1)
Index Cond: (id1 = 1)
Heap Fetches: 1
Planning Time: 0.286 ms
Execution Time: 0.044 ms
(5 rows)

可以看到,虽然SQL 只访问一条记录,但 heap fetches 值是 1 ,也就是实际需要访问表。

3、原因分析

test=# select pg_relation_filepath('t1');
pg_relation_filepath
----------------------
base/16089/16428
(1 row)

查看该路径下是否有 vm 文件。没有visibility map,postgresql就不知道是否所有的行对当前事务都是可见的,因此需要去访问表获取数据。只有fsm ,没有vm

[kb21@dbhost03 data]$ ls -l base/16089/16428*
-rw------- 1 kb21 kb21 122880 Sep 20 09:54 base/16089/16428
-rw------- 1 kb21 kb21 24576 Sep 20 09:54 base/16089/16428_fsm

4、vacuum 后执行计划

test=# vacuum analyze t1;
VACUUM
test=# explain analyze select id2 from t1 where id1=1;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Index Only Scan using ind_t1 on t1 (cost=0.14..4.16 rows=1 width=4) (actual time=0.011..0.012 rows=1 loops=1)
Index Cond: (id1 = 1)
Heap Fetches: 0
Planning Time: 0.249 ms
Execution Time: 0.031 ms
(5 rows)

vacuum 后,heap fetches 变为 0

二、进一步分析

1、通过 sys_visibility 扩展进行分析

test=# create extension  sys_visibility;
CREATE EXTENSION
test=# \dx+ sys_visibility
Objects in extension "sys_visibility"
Object description
-----------------------------------------------
function pg_check_frozen(regclass)
function pg_check_visible(regclass)
function pg_truncate_visibility_map(regclass)
function pg_visibility_map(regclass)
function pg_visibility_map(regclass,bigint)
function pg_visibility_map_summary(regclass)
function pg_visibility(regclass)
function pg_visibility(regclass,bigint)

pg_visibility_map 函数的参数:regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean

2、删除记录

test=# begin;
BEGIN
test=# delete from t1 where id1=1;
DELETE 1
test=# rollback;
ROLLBACK
test=# select pg_visibility_map('t1'::regclass, 0);
pg_visibility_map
-------------------
(f,f)
(1 row)

test=# select pg_visibility_map('t1'::regclass, 1);
pg_visibility_map
-------------------
(t,f)
(1 row)

因为id1=1 是在数据块0,因此,数据块并不是all visible

3、验证执行计划

test=# explain analyze select id2 from t1 where id1=1;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Index Only Scan using ind_t1 on t1 (cost=0.14..4.16 rows=1 width=4) (actual time=0.016..0.017 rows=1 loops=1)
Index Cond: (id1 = 1)
Heap Fetches: 1
Planning Time: 0.054 ms
Execution Time: 0.033 ms
(5 rows) test=# explain analyze select distinct id1,id2 from t1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Unique (cost=0.14..10.14 rows=100 width=8) (actual time=0.014..0.042 rows=100 loops=1)
-> Index Only Scan using ind_t1 on t1 (cost=0.14..9.64 rows=100 width=8) (actual time=0.013..0.024 rows=100 loops=1)
Heap Fetches: 7
Planning Time: 0.057 ms
Execution Time: 0.060 ms
(5 rows) test=# vacuum analyze t1;
VACUUM
test=# explain analyze select distinct id1,id2 from t1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Unique (cost=0.14..10.14 rows=100 width=8) (actual time=0.009..0.034 rows=100 loops=1)
-> Index Only Scan using ind_t1 on t1 (cost=0.14..9.64 rows=100 width=8) (actual time=0.008..0.017 rows=100 loops=1)
Heap Fetches: 0
Planning Time: 0.213 ms
Execution Time: 0.051 ms
(5 rows)

至于在Vacuum之前 heap fetches 为什么是 7 , 没搞明白。但明确的是vacuum 之后,heap fectches 变为0.

为什么Index Only Scan却还需要访问表的更多相关文章

  1. Index Full Scan vs Index Fast Full Scan-1103

    [Oracle] Index Full Scan vs Index Fast Full Scan作者:汪海 (Wanghai) 日期:14-Aug-2005 出处:http://spaces.msn. ...

  2. index full scan/index fast full scan/index range scan

    **************************1************************************* 索引状态:          valid.      N/A .    ...

  3. 索引跳跃式扫描(INDEX SKIP SCAN)

    索引跳跃式扫描(INDEX SKIP SCAN) 索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B树索引(包括唯一性索引和非唯一性索引),它使那些在where条件中没有对目标索引 ...

  4. index unique scan 与index range scan等的区别

    存取Oracle当中扫描数据的方法(一) Oracle 是一个面向Internet计算环境的数据库.它是在数据库领域一直处于领先地位的甲骨文公司的产品.可以说Oracle关系数据库系统是目前世界上流行 ...

  5. PostgreSQL执行计划:Bitmap scan VS index only scan

    之前了解过postgresql的Bitmap scan,只是粗略地了解到是通过标记数据页面来实现数据检索的,执行计划中的的Bitmap scan一些细节并不十分清楚.这里借助一个执行计划来分析bitm ...

  6. Oracle 11G INDEX FULL SCAN 和 INDEX FAST FULL SCAN 对比分析

    SQL> drop table test; 表已删除. SQL> create table test as select * from dba_objects where 1!=1; 表已 ...

  7. 【每日一摩斯】-Index Skip Scan Feature (212391.1)

    INDEX Skip Scan,也就是索引快速扫描,一般是指谓词中不带复合索引第一列,但扫描索引块要快于扫描表的数据块,此时CBO会选择INDEX SS的方式. 官方讲的,这个概念也好理解,如果将复合 ...

  8. INDEX FAST FULL SCAN和INDEX FULL SCAN

    INDEX FULL SCAN 索引全扫描.单块读 .它扫描的结果是有序的,因为索引是有序的.它通常发生在 下面几种情况(注意:即使SQL满足以下情况 不一定会走索引全扫描) 1. SQL语句有ord ...

  9. index unique scan

    INDEX UNIQUE SCAN 索引唯一扫描.单块读 只可能发生在unique index/primary key 等值查找                      等待事件:db file s ...

随机推荐

  1. SAP 实例 5 CFW Events

    REPORT demo_custom_control . * Declarations ***************************************************** CL ...

  2. 等待唤醒机制代码实现_包子类&包子铺类和等待唤醒机制代码实现_吃货类&测试类

    资源类:包子类 设置包子的属性 皮 陷 包子的状态:有 true 没有 false public class BaoZi { //皮 String pi; //陷 String xian; //包子的 ...

  3. STM32与物联网02-网络数据收发

    在上一节中,介绍了 ESP8266 的使用方法.不过上一节中都是通过串口调试工具手动发送信息的方式来操作 ESP8266 ,这肯定不能用于实际开发.因此,本节介绍如何编写合适的程序来和 ESP8266 ...

  4. 第十二天python3 匿名函数

    python借助lambda表达式构建匿名函数: 参数列表不需要小括号: 冒号是用来分割参数列表和表达式的: 不需要使用return,表达式的值,就是匿名函数返回值: lambda表达式(匿名函数)只 ...

  5. Go语言基础二:常用的Go工具命令

    常用的Go工具命令 Go附带了一下有用的命令,这些命令可以简化开发的过程.命令通常包含的IDE中,从而使工具在整个开发环境中保持一致. go run 命令 go run命令实在开发过程中执行的最常见的 ...

  6. ArrayList的操作和对象数组

    ArrayList是List接口的一个实现类,它是程序中最常见的一种集合. ArrayList内部的数据存储结构时候数组形式,在增加或删除指定位置的元素时,会创建新的数组,效率比较低,因此不适合做大量 ...

  7. SQL Server、MySQL主从搭建,EF Core读写分离代码实现

    一.SQL Server的主从复制搭建 1.1.SQL Server主从复制结构图 SQL Server的主从通过发布订阅来实现 1.2.基于SQL Server2016实现主从 新建一个主库&quo ...

  8. 筛 sigma_k

    问题 定义 \(\sigma_k(n)\) 表示 \(n\) 的所有约数的 \(k\) 次方和,即 \[\sigma_k(n)=\sum_{d\mid n}d^k \] 问题:求 \(\sigma_k ...

  9. 论文解读(GSAT)《Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism》

    论文信息 论文标题:Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism论文作者:Siqi ...

  10. 后端编写Swagger接口管理文档

    Swagger接口管理文档 访问接口文档的网页:http://localhost:8080/swagger-ui/index.html 导入依赖 <dependency> <grou ...