为什么Index Only Scan却还需要访问表
在实际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却还需要访问表的更多相关文章
- 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. ...
- index full scan/index fast full scan/index range scan
**************************1************************************* 索引状态: valid. N/A . ...
- 索引跳跃式扫描(INDEX SKIP SCAN)
索引跳跃式扫描(INDEX SKIP SCAN) 索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B树索引(包括唯一性索引和非唯一性索引),它使那些在where条件中没有对目标索引 ...
- index unique scan 与index range scan等的区别
存取Oracle当中扫描数据的方法(一) Oracle 是一个面向Internet计算环境的数据库.它是在数据库领域一直处于领先地位的甲骨文公司的产品.可以说Oracle关系数据库系统是目前世界上流行 ...
- PostgreSQL执行计划:Bitmap scan VS index only scan
之前了解过postgresql的Bitmap scan,只是粗略地了解到是通过标记数据页面来实现数据检索的,执行计划中的的Bitmap scan一些细节并不十分清楚.这里借助一个执行计划来分析bitm ...
- 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; 表已 ...
- 【每日一摩斯】-Index Skip Scan Feature (212391.1)
INDEX Skip Scan,也就是索引快速扫描,一般是指谓词中不带复合索引第一列,但扫描索引块要快于扫描表的数据块,此时CBO会选择INDEX SS的方式. 官方讲的,这个概念也好理解,如果将复合 ...
- INDEX FAST FULL SCAN和INDEX FULL SCAN
INDEX FULL SCAN 索引全扫描.单块读 .它扫描的结果是有序的,因为索引是有序的.它通常发生在 下面几种情况(注意:即使SQL满足以下情况 不一定会走索引全扫描) 1. SQL语句有ord ...
- index unique scan
INDEX UNIQUE SCAN 索引唯一扫描.单块读 只可能发生在unique index/primary key 等值查找 等待事件:db file s ...
随机推荐
- 图片放在div中低下会出现一条缝
页面要达到的样子 中间写的是时候是向div里面放一张图片就行了 <head> <link rel="stylesheet" href="reset.cs ...
- 微服务追踪SQL(支持Isto管控下的gorm查询追踪)
效果图 SQL的追踪正确插入到微服务的调用链之间 详细记录了SQL的执行内容和消耗时间 搜索SQL的类型 多线程(goroutine)下的追踪效果 在 Kubernetes 中部署微服务后,通过 Is ...
- lerna源码阅读
能够找到入口文件 能够本地调试
- 写出个灵活的系统竟然可以如此简单!小白也能写出高级的Java业务!
一 最近正好公司里有个需求,一个短信业务接了多个第三方供应商,某些业务需要查询第三方供应商剩余的短信包数量去选择剩余量最多的渠道去批量发送.有些业务是指定了某个短信供应商,有些场景需要根据业务的值去动 ...
- Tomcat深入浅出——最终章(六)
前言 利用了六天的时间,对Tomcat的内容进行了整理. 学习不易.整理也不易,自己坚持的更了下来,很不错. 希望每一位在努力前行的小伙伴,都要相信坚持就会有收获. 本次Tomcat就探寻到这里,明年 ...
- CodeQL使用流程
前言 好久没用CodeQL了,看了自己之前写的文章发现竟然没有做过相关记录 然后就不知道怎么用了hhh 使用流程 0x1 生成数据库 我们拿到一套源码,首先需要使用CodeQL生成数据库 执行命令: ...
- .Net CLR GC 动态加载短暂堆阈值的计算及阈值超量的计算
前言: 很多书籍或者很多文章,对于CLR或者GC这块只限于长篇大论的理论性概念,对于里面的如何运作模式,却几乎一无所知.高达近百万行的CPP文件,毕竟读懂的没有几个.以下取自CLR.Net 6 Pre ...
- openstack 虚拟机网卡被重名为cirename0
虚拟机网卡被重名为cirename0 在虚拟机挂载多网卡情况下,你在虚拟机上卸载网卡后,再创建新的port挂给虚拟机使用,如果虚拟机不经过重启的话,是不会有任何问题的.但是,如果虚拟机重启了,你 ...
- 修改 hosts
不会牛逼操作 -1. 位置.格式 所有系统都差不多,都是 啥啥/etc/hosts 这样的 . 具体去查即可 . 格式: ip + 域名 域名不能含有通配符 hosts 可以绕过 dns 解析,直接访 ...
- Odoo Session In Redis
# odoo session in redis # 一.下载安装Session in Redis免费模块 # 下载地址:https://apps.odoo.com/apps/modules/12.0/ ...