PostgreSQL索引扫描时为什么index only scan不返回ctid

我们都知道在PostgreSQL中使用索引扫描时,是通过索引中存储的ctid去表中得到数据的。同时在PostgreSQL中如果要查询的列都在索引中,我们还可以使用index only scan。

既然如此,当我们在查询中用到ctid时,是否还能使用index only scan呢?

按理来说是没有问题的,例如在Oracle中:

SQL> select rowid,id from t1 where id = 1;
---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |     1 |    25 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |     1 |    25 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------

我们的查询包含了rowid,仍然不需要回表TABLE ACCESS BY INDEX ROWID BATCHED的步骤。但是在PostgreSQL似乎并不是这样。

index only scan:

bill=# explain analyze select c1 from t1 where c1 = 10;
                                                     QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
 Index Only Scan using idx_t1 on t1  (cost=0.29..10.74 rows=523 width=4) (actual time=0.021..0.117 rows=523 loops=1)
   Index Cond: (c1 = 10)
   Heap Fetches: 0
 Planning Time: 0.076 ms
 Execution Time: 0.196 ms
(5 rows)

带上ctid后:

bill=# explain analyze select ctid,c1 from t1 where c1 = 10;
                                                   QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
 Index Scan using idx_t1 on t1  (cost=0.29..81.71 rows=523 width=10) (actual time=0.038..0.447 rows=523 loops=1)
   Index Cond: (c1 = 10)
 Planning Time: 0.098 ms
 Execution Time: 0.537 ms
(4 rows)

可以看到没有再去使用index only scan,取而代之的是普通的索引扫描。

为什么会这样呢?ctid必然是包含在任何btree索引中的,为什么用到ctid的时候就不能用index only scan?

在网上看到类似的问题:

传送门

解答是说和HOT有关,乍一看似乎有点道理,但是仔细想想,如果是HOT那么也会通过vm文件去判断多版本,那么对于ctid我们只要通过vm文件判断其可见性不是就可以了,至少当表中没有任何不可见的行时应该要使用index only scan啊。

这其实因为在使用vm文件进行可见性判断前,优化器在parse阶段就已经决定了是使用index scan还是index only scan,通过check_index_only函数来判断是否使用index only scan:

for (i = 0; i < index->ncolumns; i++)
{
	int			attno = index->indexkeys[i];
	/*
	 * For the moment, we just ignore index expressions.  It might be nice
	 * to do something with them, later.
	 */
	if (attno == 0)
		continue;
	if (index->canreturn[i])
		index_canreturn_attrs =
			bms_add_member(index_canreturn_attrs,
						   attno - FirstLowInvalidHeapAttributeNumber);
	else
		index_cannotreturn_attrs =
			bms_add_member(index_cannotreturn_attrs,
						   attno - FirstLowInvalidHeapAttributeNumber);
}
index_canreturn_attrs = bms_del_members(index_canreturn_attrs,
										index_cannotreturn_attrs);
/* Do we have all the necessary attributes? */
result = bms_is_subset(attrs_used, index_canreturn_attrs);

简单解释下上面这段代码的逻辑,pg在判断是否使用index only scan时,就是将索引列取出放到一个bitmap位图index_canreturn_attrs中,将查询用到的列放到一个bitmap位图attrs_used中,然后判断attrs_used位图是否是index_canreturn_attrs的子集,如果是则使用index only scan,而这里的index_canreturn_attrs信息是从pg_index中去获取的,自然是不会存放ctid的信息。

到此这篇关于PostgreSQL索引扫描时为什么index only scan不返回ctid的文章就介绍到这了,更多相关PostgreSQL index only scan内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • PostgreSQL之INDEX 索引详解

    之前总结了PostgreSQL的序列相关知识,今天总结下索引. 我们都知道,数据库索引最主要的作用是可以提高检索数据的速度,但是索引也不是越多越好.因为索引会增加数据库的存储空间,查询数据是要花较多的时间. 1.创建索引 SQL语句如下: CREATE INDEX idx_commodity ON commodity //表名 USING btree //用B树实现 (commodity_id); //作用的具体列 2.删除索引 DROP index idx_commodity; 3.增加索引的

  • postgresql通过索引优化查询速度操作

    当数据量比较大的时候,提升查询效率就是需要去考虑的事情了.一个百万级别的表格,如果不做任何优化的话,即使是最简单的查询语句执行起来也是慢的让人难以接受:当然"优化"本身是一个比较复杂的工程,从设计表.字段到查询语句的写法都有很多讲究,这里只考虑索引的方式,且是最普通的索引: 下面的操作中对应数据库表w008_execrise_info(8000数据量), w008_wf02_info(4000数据量) 1 任务表数据 SELECT w.* FROM w008_wf02_info w W

  • PostgreSql 重建索引的操作

    PostgreSql数据库的重建索引时通过REINDEX命令来实现的,如reindexindex_name: 其语法是: REINDEX { INDEX | TABLE | DATABASE | SYSTEM } name [ FORCE ]; 下面解释下说明情况下需要: 1.当由于软件bug或者硬件原因导致的索引不再可用,索引的数据不再可用: 2.当索引包含许多空的或者近似于空的页,这个在b-tree索引会发生.Reindex会腾出空间释放哪些无用的页(页就是存放数据的一个单位,类似于bloc

  • PostgreSQL索引扫描时为什么index only scan不返回ctid

    我们都知道在PostgreSQL中使用索引扫描时,是通过索引中存储的ctid去表中得到数据的.同时在PostgreSQL中如果要查询的列都在索引中,我们还可以使用index only scan. 既然如此,当我们在查询中用到ctid时,是否还能使用index only scan呢? 按理来说是没有问题的,例如在Oracle中: SQL> select rowid,id from t1 where id = 1; ------------------------------------------

  • MySQL优化GROUP BY(松散索引扫描与紧凑索引扫描)

    满足GROUP BY子句的最一般的方法是扫描整个表并创建一个新的临时表,表中每个组的所有行应为连续的,然后使用该临时表来找到组并应用累积函数(如果有).在某些情况中,MySQL能够做得更好,即通过索引访问而不用创建临时表.        为GROUP BY使用索引的最重要的前提条件是所有GROUP BY列引用同一索引的属性,并且索引按顺序保存其关键字.是否用索引访问来代替临时表的使用还取决于在查询中使用了哪部分索引.为该部分指定的条件,以及选择的累积函数.        由于GROUP BY 实

  • mysql 松散的索引扫描(Loose index scan)

    优化Group By最有效的办法是当可以直接使用索引来完全获取需要group的字段.使用这个访问方法时,MySQL使用对关键字排序的索引的类型(比如BTREE索引).这使得索引中用于group的字段不必完全涵盖WHERE条件中索引对应的key.由于只包含索引中关键字的一部分,因此称为松散的索引扫描. 历史上MySQL不能做松散的索引扫描,这种方式可以扫描索引的非连续部分,假定下面的例子中,在列(a,b)上有一索引,要运行下面的查询: mysql> SELECT - FROM tbl WHERE

  • MySQL 8.0 之索引跳跃扫描(Index Skip Scan)

    前言 MySQL 8.0.13开始支持 index skip scan 也即索引跳跃扫描.该优化方式支持那些SQL在不符合组合索引最左前缀的原则的情况,优化器依然能组使用组合索引. talk is cheap ,show me the code 实践 使用官方文档的例子,构造数据 mysql> CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2)); Query OK, 0 rows affected (0.

  • postgresql 索引之 hash的使用详解

    os: ubuntu 16.04 postgresql: 9.6.8 ip 规划 192.168.56.102 node2 postgresql help create index postgres=# \h create index Command: CREATE INDEX Description: define a new index Syntax: CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON

  • 在SQL SERVER中导致索引查找变成索引扫描的问题分析

    SQL Server 中什么情况会导致其执行计划从索引查找(Index Seek)变成索引扫描(Index Scan)呢? 下面从几个方面结合上下文具体场景做了下测试.总结.归纳. 1:隐式转换会导致执行计划从索引查找(Index Seek)变为索引扫描(Index Scan) Implicit Conversion will cause index scan instead of index seek. While implicit conversions occur in SQL Serve

  • PostgreSQL索引失效会发生什么

    前段时间碰到个奇怪的索引失效的问题,实际情况类似下面这样: bill=# begin; BEGIN bill=*# create index idx_t1 on t1(id); CREATE INDEX bill=*# explain select * from t1 where id = 1; QUERY PLAN ---------------------------------------------------- Seq Scan on t1 (cost=0.00..25.88 rows

  • MySQL 使用索引扫描进行排序

    目录 安装sakila 索引扫描排序 表结构 可以使用索引扫描来做排序的情况 补足前导列 order by 中只包含一种排序 无法使用索引扫描的情况 查询条件中包含不同排序方向 查询条件中引用不在索引中的列 无法组合最左前缀时 第一列是查询范围时 where中有多个等于条件 总结 安装sakila 我们将会使用MySQL示例数据库sakila来进行sql的演示和讲解 dev.mysql.com/doc/sakila/- 索引扫描排序 MySQL有两种方式可以生成有序的结果:通过排序操作﹔或者按索

  • PostgreSQL更新表时时间戳不会自动更新的解决方法

    PostgreSQL更新表时时间戳不会自动更新的解决方法,具体如下 操作系统:CentOS7.3.1611_x64 PostgreSQL版本:9.6 问题描述 PostgreSQL执行Insert语句时,自动填入时间的功能可以在创建表时实现,但更新表时时间戳不会自动自动更新. 在mysql中可以在创建表时定义自动更新字段,比如 : create table ab ( id int, changetimestamp timestamp NOT NULL default CURRENT_TIMEST

  • 完美解决thinkphp唯一索引重复时出错的问题

    比如如下字段(g_check_id):唯一索引 如果插入数据时(g_check_id)出现相同的值的话,程序本身是会报错的. 所以做类似如下处理: 以上这篇完美解决thinkphp唯一索引重复时出错的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

随机推荐