译者注:
MySQL 8.0之前,不管是否指定索引建的排序方式,都会忽略创建索引时候指定的排序方式(语法上不会报错),最终都会创建为ASC方式的索引,
在执行查询的时候,只存在forwarded(正向)方式对索引进行扫描。
关于正向索引和反向索引,逻辑上很容易理解,这里有两个相关的概念:
正向索引或者反向(倒序)索引,两者都是在构建B树索引时候的相关字段排序方式,是B索引树的逻辑存储方式
正向扫描(forward)和反向扫描( Backward index scan;)是执行查询的过程中对B树索引的扫描方式,是数据执行计划时候的一种索引扫描方式
关于正向扫描或者反向扫描不是随意的,受sql语句中(正/反向)排序方式以及(正/反向)索引的影响
之前在sqlserver中简单写过一点类似的东西,https://www.cnblogs.com/wy123/p/5552719.html

整体上看,抛开正向索引和倒序索引,在扫描扫描的过程中,正向索引扫描的在性能上,稍微优于反向索引扫描。
不过,即便是反向索引扫描,也是优化器根据具体查询进行优化的结果,并非一个不好的选择。


原文链接:http://mysqlserverteam.com/mysql-8-0-labs-descending-indexes-in-mysql/

以下为译文:

从8.0优化器实验室发布开始,MySQL开始支持倒序索引。
正如我将在本文中详细介绍的,这个新特性可以用来消除对结果排序的需求,并在许多查询中带来性能改进。

简介

在此版本之前,所有索引都是按升序创建的。当语法本身被解析时,元数据不会被保留。例如在MySQL 5.7中:

mysql 5.7> CREATE TABLE t1 (a INT, b INT, INDEX a_desc_b_asc (a DESC, b ASC));
Query OK, 0 rows affected (0.47 sec) mysql 5.7> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
KEY `a_desc_b_asc` (`a`,`b`) <-- 创建索引时候的元数据没有被保留
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

应该注意的是,MySQL 5.7 optimizer能够反向扫描一个升序索引(按照降序排列),其成本较高

(译者注:以上是原文中写道的,MySQL 5.7中不知道怎么去判断在对索引扫描的时候,究竟是正向扫描还是反向扫描)。
如下可以进一步测试,我们可以看到正向索引扫描比反向索引扫描好~15%。
不能支持倒叙索引的主要限制是,优化器必须对混合顺序(如DESC、b ASC的顺序)使用文件排序。

MySQL 8.0中的改进

引入反向索引后,InnoDB现在可以按照降序顺序存储数据行,优化器将在查询中请求降序时利用它。
重复上面的例子,我们可以看到在创建表时索引顺序信息被正确地保留了:

mysql 8.0> CREATE TABLE t1 (a INT, b INT, INDEX a_desc_b_asc (a DESC, b ASC));
Query OK, 0 rows affected (0.47 sec) mysql 8.0> show create table t1;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1 | CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
KEY `a_desc_b_asc` (`a` DESC,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

为了区分向后和向前索引扫描,还改进了EXPLAIN的输出。
对于MySQL-5.7,除了查询2和查询6之外,我们对所有查询都使用反向索引扫描或文件排序,因为这两个查询只需要升序。

Query 1: SELECT * FROM t1 ORDER BY a DESC;

mysql 8.0> explain SELECT * FROM t1 ORDER BY a DESC;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| 1 | SIMPLE    | t1   | NULL    | index | NULL | a_desc_b_asc | 10 | NULL | 10 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

Query 2: SELECT * FROM t1 ORDER BY a ASC;

mysql 8.0> explain SELECT * FROM t1 ORDER BY a ASC;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+----------------------------------+
| 1 | SIMPLE | t1 | NULL | index | NULL | a_desc_b_asc | 10 | NULL | 10 | 100.00 | Backward index scan; Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)

Query 3: SELECT * FROM t1 ORDER BY a DESC, b ASC;

mysql 8.0> EXPLAIN SELECT * FROM t1 ORDER BY a DESC, b ASC;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | index | NULL | a_desc_b_asc | 10 | NULL | 10 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

Query 4: SELECT * FROM t1 ORDER BY a ASC, b DESC;

mysql 8.0> EXPLAIN SELECT * FROM t1 ORDER BY a ASC, b DESC;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+----------------------------------+
| 1 | SIMPLE | t1 | NULL | index | NULL | a_desc_b_asc | 10 | NULL | 10 | 100.00 | Backward index scan; Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)

Query 5: SELECT * FROM t1 ORDER BY a DESC, b DESC;

mysql 8.0> EXPLAIN SELECT * FROM t1 ORDER BY a DESC, b DESC;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | t1 | NULL | index | NULL | a_desc_b_asc | 10 | NULL | 10 | 100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.01 sec)

Query 5: SELECT * FROM t1 ORDER BY a ASC, b ASC;

mysql 8.0> EXPLAIN SELECT * FROM t1 ORDER BY a ASC, b ASC;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | t1 | NULL | index | NULL | a_desc_b_asc | 10 | NULL | 10 | 100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

当表中有一个索引a_desc_b_asc (a DESC, b ASC)时,以下是上述6个查询的性能指标。

数据大小为1000万行。在MySQL-5.7中,它是a_asc_b_asc(a ASC, b ASC),因为不支持倒叙索引。

性能指标的解释:

1, 对于查询1,也即ORDER BY a DESC;:
我们看到查询1中性能的提升,因为请求的语句排序是“a”列的DESC
译者注:因为MySQL8.0中可以建立倒叙索引,查询1按照a字段desc排序,直接走正向(forwarded)索引扫描即可完成查询,
避免了在MySQL5.7中查询出来数据之后再进行排序操作的步骤

2,对于查询2:
由于查询2的排序为正序(译者注:与索引的顺序相反,因此需要反向扫描),由于反向索引扫描,
在MySQL-8.0中(相对于查询1)执行向反向索引扫描需要更多的时间
(注意,从图中可以看出,MySQL-8.0总体上表现更好。MySQL 5.7中正向索引扫描,与MySQL 8.0中反向索引扫描花费的时间(几乎)相同)

3,对于查询3 也即ORDER BY a DESC, b ASC;:
查询3的排序方式与查询1类似,然而在MySQL-5.7中,对于任何请求混合顺序的查询,会对查询结果重新排序,因此性能差别是巨大的。

4,对于查询4 也即 ORDER BY a ASC, b DESC;
可以看到,在MySQL 8.0中,查询4执行的是反向索引扫描,因此比查询3花费了更多的时间,
尽管如此,在查询5和查询6中,排序的方式是(a DESC, b DESC)/(a ASC, b ASC),不管是正向扫描还是反向扫描,都无法满足排序需求,因此会用到filesort
但是,在这种情况下,由于在MySQL-5.7中ASC/DESC索引标志被忽略(译者注:MySQL 5.7中没有正向和反向索引的概念),因此MySQL-5.7可以使用(正向/反向)索引扫描来给出请求的顺序。

5,如果用户想要避免查询5和查询6的filesorts,可以修改表以添加一个键(a ASC, b ASC)。
此外,如果用户也想避免反向索引扫描,可以同时添加(a ASC, b DESC)和(a DESC, b DESC)。

下面是添加了第5点下的额外索引后的MySQL-5.7.14和MySQL-8.0-labs的最后对比:

注意,在MySQL-5.7中,我们不能添加额外的索引来提高上述查询的性能。
而且,有了这个特性,在某些情况下可以避免物化,比如在连接中的第一个表上请求混合顺序。
在一些用例中,反向索引提高了性能。区间扫描访问方法也使用反向索引。
虽然并不是所有的范围扫描访问方法都使用反向索引,但我们将在未来尝试消除这些限制。

改进

随着倒序索引(反向索引)的引入,我们已经删除了对隐式排序的支持,结果是作为GROUP BY的一部分提到的列的升序。
除了上述改进外,我们还看到在一些情况下性能得到了改善,这些情况下的顺序是隐含的,但可能不是必需的。

总结

我们很高兴能够解决MySQL社区长期存在的功能请求之一。请了解倒叙索引的特性,让我们知道你的想法!

 

(译)MySQL 8.0实验室---MySQL中的倒序索引(Descending Indexes)的更多相关文章

  1. mysql jdbc8.0连接mysql

  2. MySQL 8.0有什么新功能

    https://mysqlserverteam.com/whats-new-in-mysql-8-0-generally-available/ 我们自豪地宣布MySQL 8.0的一般可用性. 现在下载 ...

  3. mysql 8.0 初识

    1 下载并安装mysql 8.0官网下载比较慢,这里选择163的镜像http://mirrors.163.com/mysql/Downloads/MySQL-8.0/下载版本mysql-8.0.14- ...

  4. MySQL 8.0部分弃用的参数整理

    最近整理了一下MySQL 8.0的自动化安装,其中用到了一个MySQL 5.7版本的自定义配置文件,由于没有对(MySQL 8.0)做针对性修改,导致安装过程中出现了一些错误其中部分原因就是MySQL ...

  5. MySQL 8.0 技术详解

    MySQL 8.0 简介 MySQL 5.7 到 8.0,Oracle 官方跳跃了 Major Version 版本号,随之而来的就是在 MySQL 8.0 上做了许多重大更新,在往企业级数据库的路上 ...

  6. mysql系列十一、mysql优化笔记:表设计、sql优化、配置优化

    可以从这些方面进行优化: 数据库(表)设计合理 SQL语句优化 数据库配置优化 系统层.硬件层优化 数据库设计 关系数据库三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非 ...

  7. SET FOREIGN_KEY_CHECKS=0;在Mysql中取消外键约束。

    SET FOREIGN_KEY_CHECKS=0;在Mysql中取消外键约束.

  8. MySQL 8.0 中统计信息直方图的尝试

    直方图是表上某个字段在按照一定百分比和规律采样后的数据分布的一种描述,最重要的作用之一就是根据查询条件,预估符合条件的数据量,为sql执行计划的生成提供重要的依据在MySQL 8.0之前的版本中,My ...

  9. MySQL 并行复制演进及 MySQL 8.0 中基于 WriteSet 的优化

    MySQL 8.0 可以说是MySQL发展历史上里程碑式的一个版本,包括了多个重大更新,目前 Generally Available 版本已经已经发布,正式版本即将发布,在此将介绍8.0版本中引入的一 ...

随机推荐

  1. 【配置阿里云 I】申请配置阿里云服务器,并部署IIS和开发环境,项目上线经验

    https://blog.csdn.net/vapaad1/article/details/78769520 最近一年在实验室做web后端开发,涉及到一些和服务器搭建及部署上线项目的相关经验,写个帖子 ...

  2. CSS 不规则图形绘制

    基础技能1 - 神奇的border 我们先来画一个长方形: .Rectangle { height: 100px; width: 200px; background: darkgray; border ...

  3. nginx1.14.0版本location路径配置四种方式

    假设下面四种情况分别用 http://192.168.1.1/proxy/test.html 进行访问. 第一种:location /proxy/ {    proxy_pass http:// 12 ...

  4. Spring核心模块:IoC容器介绍

    1.IoC容器运用的是控制反转模式. 2.IoC容器负责管理对象之间的依赖关系,并完成对象的注入. 3.在IoC设计中,会将依赖关系注入到特定组件中,其中setter注入和构造器注入是主要的注入方式. ...

  5. EChart 猜猜乐

    http://m.bkbtcaicaile.hyl.life/index.html#/

  6. 关于Unity单个对象多个脚本的Update调用的时序问题

    先说几句废话, 最近在研究Unity, 这玩意用起来比较简单, 而且商店里还有各种插件, 初学者也能轻松拼凑出一个像模像样的游戏(顺便说一句,自己做着玩就无所谓了,但随便拼凑个辣鸡丢出来骗钱就不好了) ...

  7. Redis深入学习笔记(六)Redis内存分配

    Redis的高效可以说是轻量级的epoll模型和基于内存的读写共同组成的,关于epoll对于以前的select或者poll的性能优势这里不做介绍,本篇主要介绍领一个重点,Redis的内存分配原理. 获 ...

  8. codeblock 生成和使用makefile

    下载cbp2make 文件名:cbp2make-stl-rev138.tar.gz 里面有个cbp文件用codeblock打开,编译,生成的bin目录下有个执行文件. 使用命令生成Makefile . ...

  9. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.3

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  10. Oracle创建用户、授权、规则

    ---用户登录命令--管理员登录conn sys/oracle as sysdba;--创建用户方案必须是管理员权限--创建用户命令 create user useranme identifild b ...