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.21 sec)
mysql> INSERT INTO t1 VALUES (1,1), (1,2), (1,3), (1,4), (1,5),(2,1), (2,2), (2,3), (2,4), (2,5);
Query OK, 10 rows affected (0.07 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql>
mysql> INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
Query OK, 10 rows affected (0.06 sec)
Records: 10 Duplicates: 0 Warnings: 0

mysql> INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
Query OK, 20 rows affected (0.03 sec)
Records: 20 Duplicates: 0 Warnings: 0

mysql> INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
Query OK, 40 rows affected (0.03 sec)
Records: 40 Duplicates: 0 Warnings: 0

mysql> INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
Query OK, 80 rows affected (0.05 sec)
Records: 80 Duplicates: 0 Warnings: 0

注意t1表的主键是组合索引(f1,f2),如果sql的where条件不包含 最左前缀f1 在之前的版本中会 走 FULL TABLE SCAN,在MySQL 8.0.20版本中会是怎样呢?我们看看执行计划

mysql> EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 = 40\G
*************************** 1. row ***************************
      id: 1
 select_type: SIMPLE
    table: t1
  partitions: NULL
     type: range
possible_keys: PRIMARY
     key: PRIMARY
   key_len: 8
     ref: NULL
     rows: 16
   filtered: 100.00
    Extra: Using where; Using index for skip scan
1 row in set, 1 warning (0.01 sec)

mysql> EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40\G
*************************** 1. row ***************************
      id: 1
 select_type: SIMPLE
    table: t1
  partitions: NULL
     type: range
possible_keys: PRIMARY
     key: PRIMARY
   key_len: 8
     ref: NULL
     rows: 53
   filtered: 100.00
    Extra: Using where; Using index for skip scan
1 row in set, 1 warning (0.00 sec)

两个sql 的where条件 f2>40 和 f2=40 的执行计划中都包含了Using index for skip scan 并且 type 是range 。

整个执行计划大概如下:

第一次从Index left side开始scan
第二次使用key(1,40) 扫描index,直到第一个range结束
使用key(1), find_flag =HA_READ_AFTER_KEY, 找到下一个Key值2
使用key(2,40),扫描Index, 直到range结束
使用Key(2),去找大于2的key值,上例中没有,因此结束扫描

从上述描述可以看到使用skip-scan的方式避免了全索引扫描,从而提升了性能

如果关闭 skip_scan特性,执行计划则变为type=all, extre using where 全表扫描。

mysql> set session optimizer_switch='skip_scan=off';
Query OK, 0 rows affected (0.01 sec)

mysql> EXPLAIN SELECT * FROM t1 WHERE f2 = 40\G
*************************** 1. row ***************************
      id: 1
 select_type: SIMPLE
    table: t1
  partitions: NULL
     type: ALL
possible_keys: NULL
     key: NULL
   key_len: NULL
     ref: NULL
     rows: 160
   filtered: 10.00
    Extra: Using where
1 row in set, 1 warning (0.00 sec)

限制条件

1.select 选择的字段不能包含非索引字段

比如c1 字段在组合索引里面 ,select * 的sql 就走不了skip scan

mysql> EXPLAIN SELECT * FROM t1 WHERE f2 = 40\G
*************************** 1. row ***************************
      id: 1
 select_type: SIMPLE
    table: t1
  partitions: NULL
     type: ALL
possible_keys: NULL
     key: NULL
   key_len: NULL
     ref: NULL
     rows: 160
   filtered: 10.00
    Extra: Using where
1 row in set, 1 warning (0.00 sec)

2.sql 中不能带 group by或者distinct 语法

mysql> EXPLAIN SELECT distinct f1 FROM t1 WHERE f2 = 40\G
*************************** 1. row ***************************
      id: 1
 select_type: SIMPLE
    table: t1
  partitions: NULL
     type: range
possible_keys: PRIMARY
     key: PRIMARY
   key_len: 8
     ref: NULL
     rows: 3
   filtered: 100.00
    Extra: Using where; Using index for group-by
1 row in set, 1 warning (0.01 sec)

3.Skip scan仅支持单表查询,多表关联是无法使用该特性。

4.对于组合索引 ([A_1, …, A_k,] B_1, …, B_m, C [, D_1, …, D_n]),A,D 可以为空,但是B ,C 字段不能为空。

需要强调的是数据库优化没有银弹。MySQL的优化器是基于成本来选择合适的执行计划,并不是所有的忽略最左前缀的条件查询,都能利用到 index skip scan。

举个例子:

mysql> CREATE TABLE `t3`
( id int not null auto_increment PRIMARY KEY,
`f1` int NOT NULL,
`f2` int NOT NULL,
`c1` int DEFAULT '0',
key idx_f12(`f1`,`f2`,c1) )
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.24 sec)

mysql> insert into t3(f1,f2,c1) select f1,f2,c1 from t1;
Query OK, 320 rows affected (0.07 sec)
Records: 320 Duplicates: 0 Warnings: 0

数据量增加一倍到320行记录,此时查询 f2=40 也没有利用index skip scan

mysql> explain select f2 from t3 where f2=40 \G
*************************** 1. row ***************************
      id: 1
 select_type: SIMPLE
    table: t3
  partitions: NULL
     type: index
possible_keys: idx_f12
     key: idx_f12
   key_len: 13
     ref: NULL
     rows: 320
   filtered: 10.00
    Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)

-The End-

以上就是MySQL 8.0 之索引跳跃扫描(Index Skip Scan)的详细内容,更多关于MySQL 8.0 索引跳跃扫描的资料请关注我们其它相关文章!

(0)

相关推荐

  • 浅谈MySQL8.0 异步复制的三种方式

    本实验中分别针对空库.脱机.联机三种方式,配置一主两从的mysql标准异步复制.只做整服务器级别的复制,不考虑对个别库表或使用过滤复制的情况. 实验环境 [root@slave2 ~]# cat /etc/hosts 192.168.2.138 master 192.168.2.192 slave1 192.168.2.130 slave2 mysql> select version(); +-----------+ | version() | +-----------+ | 8.0.16 |

  • MySQL8.0.21.0社区版安装教程(图文详解)

    一.下载MySQL 登录MySQL官网下载MSI Installer: 点击"Dnownload" 点击"No thanks, just start my download." 二.安装MySQL Step1:选择安装类型 根据个人需求,选择其中一个安装类型: Developer Default 开发者默认安装 Server only 仅安装服务端(推荐) Client only 仅安装客户端 Full 安装所有内容 Custom 自定义安装(推荐) 点击"

  • mysql8.0.20配合binlog2sql的配置和简单备份恢复的步骤详解

    第一步 安装 1.安装MySQL 2.安装Python3 [root@localhost /]#yum install python3 3.下载binlog2sql文件到本地(文件在百度云盘) [root@localhost /]#mkdir tools [root@localhost /]#cd tools [root@localhost tools]# ll total 317440 -rw-r--r--. 1 root root 317440 Sep 21 23:55 binlog2sql

  • MySQL8.0 如何快速加列

    前言: 很早就听说 MySQL8.0 支持快速加列,可以实现大表秒级加字段.笔者自己本地也有8.0环境,但一直未进行测试.本篇文章我们就一起来看下 MySQL8.0 快速加列到底要如何操作. 1.了解背景信息 表结构的变更是业务运行过程中比较常见的需求之一,在 MySQL 的环境中,可以使用 Alter 语句来完成这些操作,这些 Alter 语句对应的操作通常也称之为 DDL 操作.通常情况下大表的 DDL 操作都会对业务有很明显的影响,需要在业务空闲,或者是维护的时候做.MySQL 5.7 支

  • MySQL8.0窗口函数入门实践及总结

    前言 MySQL8.0之前,做数据排名统计等相当痛苦,因为没有像Oracle.SQL SERVER .PostgreSQL等其他数据库那样的窗口函数.但随着MySQL8.0中新增了窗口函数之后,针对这类统计就再也不是事了,本文就以常用的排序实例介绍MySQL的窗口函数. 1.准备工作 创建表及测试数据 mysql> use testdb; Database changed /* 创建表 */ mysql> create table tb_score(id int primary key aut

  • VS2019连接mysql8.0数据库的教程图文详解

    1.首先准备好VS2019以及mysql数据库,两者都可以去官网下载,我们直接描述连接过程. 2.连接: 第一步:打开mysql的安装目录,我本地的安装目录如下:(注意是否有include和lib文件夹) 第二步:打开VS2019,新建一个空工程. 第三步:右击工程名,打开属性页: 第四步:打开VC++目录,在包含目录中,将mysql安装文件中的include文件的路径添加到这里: 第五步:还是在属性页上,打开C/C++,选择常规,和上一步一样,在附加包含目录中将mysql文件中的include

  • mysql8.0.21下载安装详细教程

    官网地址:https://www.mysql.com/ 安装建议:尽量不要用.exe进行安装,用压缩包安装,对日后的卸载更为方便 下载地址:https://dev.mysql.com/downloads/mysql/ 1.下载得到zip压缩包 2.解压到要安装的目录 我这里是:D:\Program File\MySQL\mysql-8.0.21-winx64,增加了data目录 3.添加环境变量 我的电脑–>属性–>高级–>环境变量 选择path添加:mysql安装目录下的bin文件夹地

  • mysql8.0.21安装教程图文详解

    1.下载 下载链接 点击download,这里可能需要登录甲骨文的账号,登录一下即可 2.解压 下载好会得到一个安装包 把它解压到一个能找到的目录下即可,我的是这样(my.ini文件你们应该没有) 3.新建my.ini 如图,新建一个文件,后缀名改成ini.文件名最好不要改 打开文件,将下面的代码粘贴复制进去 [mysqld] # 设置3306端口 port=3306 # 设置mysql的安装目录 basedir=D:\\mysql-8.0.21-winx64 # 设置mysql数据库的数据的存

  • mysql8.0.20安装与连接navicat的方法及注意事项

    需要注意的地方 1.首先需要在mysql的安装目录下新建一个my.ini文件,内容如下: [client] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] # 设置3306端口 port = 3306 # 设置mysql的安装目录 basedir=C:\\web\\mysql-8.0.11 # 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错 # datadir=C:\\web\

  • 解析MySQL8.0新特性——事务性数据字典与原子DDL

    前言 事务性数据字典与原子DDL,是MySQL 8.0推出的两个非常重要的新特性,之所以将这两个新特性放在一起,是因为两者密切相关,事务性数据字典是前提,原子DDL是一个重要应用场景. MySQL 8.0之前的数据字典 MySQL 8.0之前的数据字典,主要由以下三部分组成: (1)操作系统文件 db.opt:数据库元数据信息 frm:表元数据信息 par:表分区元数据信息 TRN/TRG:触发器元数据信息 ddl_log.log:DDL过程中产生的元数据信息 (2)mysql库下的非InnoD

  • MySQL8.0内存相关参数总结

    MySQL理论上使用的内存 = 全局共享内存 + max_connections×线程独享内存. 也就是:innodb_buffer_pool_size + innodb_log_buffer_size + thread_cache_size +table_open_cache + table_definition_cache +key_buffer_size + max_connections *( thread_stack+ sort_buffer_size+join_buffer_size

  • Windows系统下MySQL8.0.21安装教程(图文详解)

    安装建议:尽量不要用.exe进行安装,用压缩包安装,对日后的卸载/版本升级更为方便 下载地址:https://dev.mysql.com/downloads/mysql/ 1.点击上面的下载地址得到zip压缩包 2.解压到要安装的目录 我这里是E:\database\mysql8\mysql-8.0.21-winx64\bin data 文件夹与 my.ini文件需手动创建出来 3.添加环境变量 我的电脑–>属性–>高级系统设置–>环境变量 选择path添加:mysql安装目录下的bin

  • MySQL8.0.20压缩版本安装教程图文详解

    1.MySQL下载地址: http://ftp.ntu.edu.tw/MySQL/Downloads/MySQL-Cluster-8.0/ 2.解压以后放在一个文件夹里面,创建my.ini配置文件: my.ini文件内容: [mysqld] character-set-server=utf8 bind-address = 0.0.0.0 port = 3306 #配置mysql的解压路径,需要手动更改 basedir=D:\installtools\mysql-8.0.20-winx64 #配置

随机推荐