跳跃范围扫描是MySQL在8.0.13版本新增长的用于提升性能的新特性,跳跃范围扫描可使之前部分没法使用到联合索引的SQL利用联合索引进行查询,而且能够更高效的利用联合索引,这对于使用MySQL联合索引进行查询的应用意义重大。mysql
经过一个示例来解释跳跃范围扫描:sql
CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2));
INSERT INTO t1 VALUES(1,1), (1,2), (1,3), (1,4), (1,5),(2,1), (2,2), (2,3), (2,4), (2,5);
INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
ANALYZE TABLE t1;
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)
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.15 |
+-----------+
1 row in set (0.00 sec)
复制代码
在这个示例中,SELECT f1,f2 FROM t1 WHERE f2>40
在8.0.13版本以前是经过索引全扫描的方式来获取最终的结果集,由于SELECT查询的字段所有都是索引的组成部分。MySQL经过索引全扫描获取全部的行记录,而后经过f2 > 40
这个条件过滤,最终筛选出结果集返回给客户端。bash
众所周知,索引范围扫描的效率确定是要高于索引全扫描的,在这个示例中,虽然查询条件是f2 > 40
,属于范围查询,可是WHERE条件中不包含f1
字段的的条件,因此没法使用索引范围扫描的方式过滤数据。在MySQL-8.0.13版本增长的跳跃范围扫描特性,就是针对相似的场景的优化,跳跃范围扫描在这个示例中实际是针对每个f1
字段的值,进行了范围扫描,即进行了屡次范围扫描。 针对这个示例,具体的跳跃范围扫描过程以下:性能
f1
的第一个值:f1 = 1
f2
的条件组合:f1 = 1 AND f2 > 40
f1
的第二个值:f1 = 2
f2
的条件组合:f1 = 2 AND f2 > 40
跳跃范围扫描实际就是将一些全扫描的场景拆分红多个范围扫描,利用范围扫描的效率高于全扫描的效率,最终实现提升SQL效率。 在这个示例中,比较有跳跃范围扫描特性的SQL执行计划以及没有跳跃范围扫描特性的SQL执行计划:优化
# 有跳跃范围扫描特性
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)
# 没有跳跃范围扫描特性
mysql> EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: index
possible_keys: NULL
key: PRIMARY
key_len: 8
ref: NULL
rows: 160
filtered: 33.33
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
复制代码
经过执行计划能够看到,有跳跃范围扫描特性的查询扫描的行数更少且过滤性更高。ui
下面来讲说跳跃范围扫描使用一些限制以及场景:spa
([A_1,A_2...A_k],B_1,B_2...B_m,C,[,D_1,...,D_n])
,其中A部分以及D部分能够为空,可是B和C部分不能为空。A_1,A_2..等表明字段值GROUP BY
或者DISTINCT
A_1,A_2...A_k
部分必须是能够被相等的常量跳跃范围扫描默认是开启的,有两种方式能够关闭跳跃范围扫描特性:操作系统
optimizer_switcher
变量值,默认MySQL是将optimizer_switcher
中的skip_scan
设置为on的,能够经过将skip_scan
设置为off关闭跳跃范围扫描SELECT/*+ NO_SKIP_SCAN(t1 PRIMARY) */ f1, f2 FROM t1 WHERE f2 > 40;
对于使用了跳跃范围扫描特性的SQL,使用EXPLAIN查看其执行计划,能够看到:code
Using index for skip scan
跳跃范围扫描是对使用MySQL联合索引查询的SQL意义重大,能在使SQL查询效率更高,可是并非使用到跳跃范围扫描就能表明SQL执行效率更高。在MySQL一些开发规范中,通常要求创建联合索引时将重复值少的字段放在联合索引前面,将重复值多的字段放在联合索引后面,方便SQL在使用联合索引时经过前面的字段快速过滤结果。可是在跳跃范围扫描特性中,是遍历前面字段的值,与后续字段的范围查询条件组合,进行范围扫描查询,那对于重复值少的字段会被拆分红多个范围扫描查询,在实际使用过程当中并不必定会比索引全扫描效率更高。索引
因此我的以为跳跃范围扫描适用于联合索引中前导列distinct值较少,后续字段选择过滤性又比较好的场景,能更好的发挥跳跃范围扫描的做用。