在实际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. Canal实现MySQL协议

    目录 代码流程 执行dump前 执行dump 在学习Canal的时候很好奇Canal是如何模拟成MySql Slave来接收数据的 MySql Slave会向主库发送dump协议来接收bin-log数 ...

  2. nginx 出现An error occurred错误

    原因是我nginx中conf文件的配置里面 location中的 这一块内容是 #注释的那两行 所以报错出现这个错误. 后来将这两行注释掉,改成这两个就好了. root html; index ind ...

  3. MYSQL中IF IN语句

    以下代码摘自后台管理系统中的一部分SQL语句: 当取数状态为1或2时,才展示取数时间,否则,取数时间展示为空 当申报状态为2.3.4或5时,才展示申报时间,否则,申报时间展示为空 select A.Q ...

  4. 基于后端和爬虫创建的代理ip池

    搭建免费的代理ip池 需要解决的问题: 使用什么方式存储ip 文件存储 缺点: 打开文件修改文件操作较麻烦 mysql 缺点: 查询速度较慢 mongodb 缺点: 查询速度较慢. 没有查重功能 re ...

  5. 选择结构-穿透的switch语句和循环结构-循环概述

     case的穿透性 在switch语句中,如果case的后面不写break,将出现穿透现象,也就是不会在判断下一个case的值,直接向后运 行,直到遇到break,或者整体switch结束 publi ...

  6. APISpace 周公解梦API接口 免费好用

    <周公解梦>,是根据人的梦来卜吉凶的一本解梦书籍,它对人的七类梦境进行解述.   周公解梦API,周公解梦大全,周公解梦查询,免费周公解梦.   APISpace 有很多免费通用的API接 ...

  7. 论文阅读 A Data-Driven Graph Generative Model for Temporal Interaction Networks

    13 A Data-Driven Graph Generative Model for Temporal Interaction Networks link:https://scholar.googl ...

  8. 【Kaggle】如何有效避免OOM(out of memory)和漫长的炼丹过程

    本文介绍一些避免transformers的OOM以及训练等流程太漫长的方法,主要参考了kaggle notebook Optimization approaches for Transformers ...

  9. 第十五天python3 文件IO(一)

    一.文件打开 open(path,flag[,encoding][,errors]) 参数说明: path:要打开文件的路径 flag:打开方式( r:以只读的方式打开文件,文件的描述符放在文件开头 ...

  10. 第十天python3 函数的销毁

    全局函数销毁 三种方式: 1.重新定义同名函数 2.del语句删除函数对象 3.程序结束时 局部函数销毁 三种方式: 1.重新在上级作用域定义同名函数: 2.del语句删除函数对象: 3.上级作用域销 ...