PostgreSQL 11 新特性之覆盖索引(Covering Index)(转载)
有时候,索引不仅仅能够用于定位表中的数据。某些查询可能只需要访问索引的数据,就能够获取所需要的结果,而不需要再次访问表中的数据。这种访问数据的方法叫做 Index-Only 扫描。
要想通过索引直接返回查询的数据,创建的索引需要包含 SELECT 列表中的所有字段:
CREATE TABLE t1 (a int, b int, c int);
SELECT val, val + 1, val * 2
FROM generate_series(1, 100000) as val;
CREATE UNIQUE INDEX idx_t1_ab ON t1(a, b);
ANALYZE;
12345678
以下查询使用字段 a 作为条件,并返回 a 和 b:
EXPLAIN SELECT a, b FROM t1 WHERE a BETWEEN 100 AND 200;
QUERY PLAN |
--------------------------------------------------------------------------|
Index Only Scan using idx_t1_ab on t1 (cost=0.29..166.00 rows=98 width=8)|
Index Cond: ((a >= 100) AND (a <= 200)) |
12345
通过查询计划可以看出,以上查询使用了 Index-Only Scan,直接通过索引扫描就可以返回查询的结果。
许多数据库产品对于这种包含了查询结果的索引称为覆盖索引(covering index),不过更准确的说法应该是 Index-Only 扫描。它只是执行计划访问数据的一种方式,而不是一种新的索引。
我们修改一下查询,仍然以字段 a 作为查询条件,但是要求返回 a 和 c:
EXPLAIN SELECT a, c FROM t1 WHERE a BETWEEN 100 AND 200;
QUERY PLAN |
---------------------------------------------------------------------|
Index Scan using idx_t1_ab on t1 (cost=0.29..166.00 rows=98 width=8)|
Index Cond: ((a >= 100) AND (a <= 200)) |
12345
由于字段 c 不在索引 idx_t1_ab 中,查询虽然使用了索引扫描,但是仍然需要通过索引二次查询表中的数据。如果想要使用 Index-Only 扫描,需要再基于字段 a, c 创建一个新的索引。
如果查询需要返回 a, b, c,还需要第 3 个索引。如果使用 a, b, c 上的索引替代 idx_t1_ab,又无法保证 a, b 上的唯一性。
为此,PostreSQL 11 提供了一个新的索引子句,即 INCLUDE 子句:
DROP INDEX idx_t1_ab;
ANALYZE;
1234
EXPLAIN SELECT a, c FROM t1 WHERE a BETWEEN 100 AND 200;
QUERY PLAN |
---------------------------------------------------------------------------|
Index Only Scan using idx_t1_ab on t1 (cost=0.42..176.77 rows=105 width=8)|
Index Cond: ((a >= 100) AND (a <= 200)) |
QUERY PLAN |
------------------------------------------------------------------------|
Index Only Scan using idx_t1_ab on t1 (cost=0.42..8.44 rows=1 width=12)|
Index Cond: ((a = 100) AND (b >= 100) AND (b <= 200)) |
1234567891011
接下来看一看官方文档中的介绍:
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ INCLUDE ( column_name [, ...] ) ]
[ WITH ( storage_parameter = value [, ... ] ) ]
[ TABLESPACE tablespace_name ]
[ WHERE predicate ]
123456
INCLUDE 子句可以为索引增加一些非键值的字段。这些非键字段不能用于索引的扫描条件,并且也不会参与索引的唯一性约束和排除约束。 不过,Index-Only 扫描方式可以返回这些非键字段的值,而不需要访问索引所在的表,因为可以直接从索引节点中直接返回它们的值。因此,在索引中包含非索引键的字段扩展了 Index-Only 扫描的使用场景。
使用上面的示例表:
EXPLAIN SELECT a, b, b FROM t1 WHERE a=100 and b =100 and c=100;
QUERY PLAN |
------------------------------------------------------------------------|
Index Only Scan using idx_t1_ab on t1 (cost=0.42..8.44 rows=1 width=12)|
Index Cond: ((a = 100) AND (b = 100)) |
Filter: (c = 100) |
123456
查询计划中的索引扫描条件为 ‘((a = 100) AND (b = 100))’,而 ‘(c = 100)’ 只是作为过滤条件。
另外,索引 idx_t1_ab 的唯一性只能确保字段 a, b 的组合唯一,不包括字段 c 的值。
为索引添加非键字段时需要谨慎考虑,特别是宽列。如果一个索引记录超过了索引类型允许的最大值,数据操作将会失败。此外,非键字段重复存储了表中的数据,并且增加了索引的大小,可能会导致查询变慢。
INCLUDE 子句中的列不需要相应的操作符类;该子句可以包含没有为特定访问方式定义操作符的数据类型。因为这些字段仅仅用于返回数据,而不参与索引的扫描。
表达式(函数)不能作为 INCLUDE 字段,因为 Index-Only 扫描不支持表达式。
CREATE UNIQUE INDEX idx_t1_exp ON t1(a, b) INCLUDE ((c+1));
SQL Error [0A000]: ERROR: expressions are not supported in included columns
12
目前只有 B-tree 索引支持 INCLUDE 子句。在 B-tree 索引中 ,INCLUDE 子句中的字段值只存储在叶子节点中,而不会包含在上层的导航节点中。
覆盖索引还是优化连接查询的一个非常好的方法,参考:Covering Indexes for Query Optimization
参考文章:Postgres 11 highlight - Covering Indexes
人生本来短暂,你又何必匆匆!点个赞再走吧!
————————————————
版权声明:本文为CSDN博主「董旭阳TonyDong」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/horses/article/details/85603584
PostgreSQL 11 新特性之覆盖索引(Covering Index)(转载)的更多相关文章
- Mysql覆盖索引 covering index 或者 index coverage
组合索引 提到组合索引,大家都知道"最左前缀"原则.例如,创建索引 idx_name_age (name,age) ,通常情况下,where age=50 或者 where age ...
- C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)
因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- 在C++98基础上学习C++11新特性
自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...
- C++11新特性总结 (二)
1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...
- C++11新特性总结 (一)
1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...
- C++ 11 新特性
C++11新特性: 1.auto 2.nullptr 3.for 4.lambda表达式 5.override ...
- C++11新特性——range for
很多编程语言都有range for语法功能,自C++11起,终于将这个重要功能加入C++标准中.range for语句,可以方便的遍历给定序列中的每个元素并对其执行某种操作. 1.基本语法 for(d ...
- C++11新特性——大括号初始化
C++11之前,C++主要有以下几种初始化方式: //小括号初始化 string str("hello"); //等号初始化 string str="hello" ...
随机推荐
- DFS解决八皇后问题
2019-07-29 16:49:15 #include <bits/stdc++.h> using namespace std; ][]; int tot; int check(int ...
- Linux安装centos
在虚拟机上安装centos 虚拟机使用win10自带的hyper-v非常好用 centos下载地址http://mirrors.aliyun.com/centos/7.6.1810/isos/x86_ ...
- Verilog转电路图
“你写的不是程序,是电路!”这句话听了很多,大多数人还是搞不太懂.程序怎么能是电路呢?这里将一些典型的Verilog转电路图贴出来,也许可以稍稍理解电路思想了. 1. 2. 3. 4. 5. 6. 7 ...
- Java JDK1.8源码学习之路 1 Object
写在最前 对于一个合格的后端程序员来说,现行的流行框架早已经能胜任基本的企业开发,Springboot 任何的框架都把重复的工作更佳简单/优化的解决掉,但是完全陷入在这样的温水里面, 好比温水煮青蛙, ...
- c#中冒泡排序算法描述
int temp = 0; int b = 0; int[] arr = { 23, 44, 66, 76, 98, 11, 3, 99, 7 };# region该段与排序无关Console.Wri ...
- 2.7_Database Interface OLE-DB诞生
ODBC仅支持关系数据库,以及传统的数据库类型,并且只以C/C++语言API(API就是一些C语言的代码,是最底层的程序,在windows中就是一些.dll的文件)形式提供服务,因而无法符合日渐复杂的 ...
- Java 日期时间与unix时间戳之间转换
日期时间 <--> 时间戳 java.time 包提供的新的日期和时间API LocalDateTime: 本地日期时间类 ZoneId: 时区类 ZonedDateTime: 带时区 ...
- Fortify漏洞之Denial of Service: Regular Expression
继续对Fortify的漏洞进行总结,本篇主要针对 Denial of Service: Regular Expression 漏洞进行总结,如下: 1.Denial of Service: Reg ...
- [LeetCode] 5. 最长回文子串 ☆☆☆(最长子串、动态规划)
最长回文子串 (动态规划法.中心扩展算法) https://leetcode-cn.com/problems/longest-palindromic-substring/solution/xiang- ...
- python实现进制转换(二、八、十六进制;十进制)
python实现进制转换(二.八.十六进制:十进制) (一)十进制整数转为二.八.十六进制 1.format实现转换>>> format(2,"b") # (10 ...