阿里面试官让我谈谈:Mysql中的降序索引底层实现,附20道面试题

什么是降序索引

大家可能对索引比较熟悉,而对降序索引比较陌生,事实上降序索引是索引的子集

我们通常使用下面的语句来创建一个索引:

create index idx_t1_bcd on t1(b,c,d);

上面sql的意思是在t1表中,针对b,c,d三个字段创建一个联合索引。

但是大家不知道的是,上面这个sql实际上和下面的这个sql是等价的:

create index idx_t1_bcd on t1(b asc,c asc,d asc);

`asc`表示的是升序,使用这种语法创建出来的索引叫做**升序索引**。也就是我们平时在创建索引的时候,创建的都是升序索引。

可能你会想到,在创建的索引的时候,可以针对字段设置asc,那是不是也可以设置desc呢?

当然是可以的,比如下面三个语句:

create index idx_t1_bcd on t1(b desc,c desc,d desc);create index idx_t1_bcd on t1(b asc,c desc,d desc);create index idx_t1_bcd on t1(b asc,c asc,d desc);

这种语法在mysql中也是支持的,使用这种语法创建出来的索引就叫降序索引

关键问题是:在Mysql8.0之前仅仅只是语法层面的支持,底层并没有真正支持。

我们分别使用Mysql7、Mysql8两个版本来举例子说明一下:

在Mysql7、Mysql8中分别创建一个表,有a,b,c,d,e五个字段:

create table t1 (a int primary key,b int,c int,d int,e varchar(20)) engine=InnoDB;

然后分别创建一个降序索引:

create index idx_t1_bcd on t1(b desc,c desc,d desc);

创建成功后,我们使用以下sql查看一下索引信息:

show index from t1;

Mysql7中你将得到结果:

阿里面试官让我谈谈:Mysql中的降序索引底层实现,附20道面试题

Mysql8中你将得到结果:

阿里面试官让我谈谈:Mysql中的降序索引底层实现,附20道面试题

我们只关心Key_name为idx_t1_bcd的三行记录,细心的你应该可以发现,这两个结果中的Collation字段的结果是不一样的:

• 在Mysql7中,Collation字段的结果为A,A,A,表示b,c,d三个字段的排序方式是asc

• 在Mysql8中,Collation字段的结果为D,D,D,表示b,c,d三个字段的排序方式是desc

但是我们在创建索引的时候,明明在语法层面已经指定了b,c,d三个字段的排序方式是desc,这就可以看出来在Mysql7中降序索引只是语法层面的支持,底层并没有真正支持,并且固定是升序索引。而在Mysql8中则真正从底层支持了降序索引。

到此为止,大家应该对升序索引和降序索引有了一个大概的了解,但并没有真正理解,因为大家并不知道升序索引与降序索引底层到底是如何实现的。

我们知道,索引是用来提高查询速度的,但是为什么索引能提高查询速度呢?

给定你一个数列,比如[1,3,7,9,2,5,4,6,8],这是一个无序的数列或数组,现在如果想提高这个数列的查询速度,你首先会做什么?

我相信大部分人都能够想到先排序,先把这个无序的数列,按从小到大的顺序进行排序,比如得到[1,2,3,4,5,6,7,8,9],有了这个有序的数列之后,我们就可以利用比如二分法等等算法来提高这个数列的查询速度了。

我举这个例子想告诉大家的是:想提高数据集合的查询速度,首先你可以对这些数据进行排序。

所以,对Mysql表中的存储的数据也是一样的,我们如果想提高这个表的查询速度,我们可以先对这个表里的数据进行排序,那么表里的某一行数据包括了很多字段,我们现在想对这些数据行进行排序,我们应该根据哪些字段来确定这个顺序呢?这就是索引,在创建索引的时候你所指定的列就是用来对表里的数据行进行排序的。

比如我们仍然利用上面所创建的t1表,向t1表里插入8条数据:

insert into t1 values(4,3,1,1,'d');insert into t1 values(1,1,1,1,'a');insert into t1 values(8,8,8,8,'h');insert into t1 values(2,2,2,2,'b');insert into t1 values(5,2,3,5,'e');insert into t1 values(3,3,2,2,'c');insert into t1 values(7,4,5,5,'g');insert into t1 values(6,6,4,4,'f');

那么这些数据肯定是存储在文件中的,所以文件中保存这些数据的格式大概如下,顺序与插入顺序保持一致:

4311d1111a8888h2222b5235e3322c7455g6644f

注意,t1是Innodb的存储引擎,而且a字段是主键,所以Innodb存储引擎在处理这些插入的数据时,会按主键进行排序,也就是上面我说的文件中保存这些数据的格式是不准确的。

而如果我们基于上面的这种存储方式,来查找数据,比如查找a=3的这行记录,查找需要从第一行记录开始查找,那么要查找6次,而如果我们将上面的数据按照a字段的大小来进行排序:

1111a2222b3322c4311d5235e6644f7455g8888h

排好序之后,如果我们还是查找a=3的这行记录,我们只需要查3次了。而且这样还有一个好处就是,如果我们现在需要查找a=3.5这行数据,如果我们基于未排序之前的存储方式,我们需要查询所有8行数据最终确定a=3.5这行数据不存在,而如果我们利用排好序之后的存储方式,我们就只需要查4次就好了,因为当你查到`4311d`这行记录时,你会发现4>3.5了,已经可以确定a=3.5的这行记录不存在了。

而如果我们现在对t1创建一个索引,就像上面创建索引一样,如果我们写的是下面的sql:

create index idx_t1_bcd on t1(b,c,d);

这个sql表示要对t1创建一个索引,索引字段是b,c,d,并且是升序的,所以实际上就是对原本的数据按照b,c,d三个字段进行排序,那么排序之后类似:

1111a2222b5235e4311d3322c7455g6644f8888h

可以好好看下,上面的记录是按照b,c,d三个字段来对数据行就行排序的,比如`1111a`中的b,c,d三个字段的值是`111`,而`2222b`中的b,c,d三个字段的值是`222`, `111`是小于`222`的,所以对应的行排在前面。

那么数据如果这样排序有什么好处呢?其实和刚刚按a字段排序之后的好处是类似的,比如你现在想来查找`b=4 and c=4 and d=4`的数据也是能查询更快的,实际上这就是索引的原理:

我们对某个表创建一个索引,就是对这个表中的数据进行排序,而排好序之后的数据是能够提高查询速度。

还有一点需要注意的是,排序有很多中方式,或者所可以利用一些数据结构,比如二叉树、红黑树、B+树,这些数据结构实际上就是对数据进行排序,只是排序的形式各不相同而已,每种数据结构有它各自的特点,而大家应该都知道,Mysql中用得最多的就是B+树了,还是一样。

相信,看到这里,大家应该对索引重新有了认识,只不过我们上面举的几个例子都是升序排序,而且排好序之后的数据不仅可以提高查询速度,而且对于order by也是管用的,比如我们如果现在想对t1进行`order by b asc,c asc,d asc`;对于这个排序,如果已经在t1表建立了`b,c,d的升序索引`,那么就代表对t1表中的数据已经提前按照b,c,d排好序了,所以对于order by语句可以直接使用已经排好序的数据了,不用利用filesort再次进行排序了。

而且如果我们的order by是`order by b desc, c desc, d desc`,同样可以利用b,c,d的升序索引,因为如果是order by b asc,c asc,d asc就从上往下遍历即可,如果是`order by b desc, c desc, d desc`就从下往上遍历即可。

那么,如果是`order by b asc, c desc, d desc`呢?这个order by是不是就没有办法利用`b,c,d的升序索引`了。

这个时候就需要降序索引了。

降序索引底层实现

我们花了较大篇幅介绍了升序索引的实现原理,总结来说就是对表中的数据按照指定的字段比较大小进行升序排序。

升序是什么?是数据进行大小比较后,是**小的在上,大的在下**,或者如果是B+树的话就是**小的在左,大的在右**。而降序就是**大的在上,小的在下**,或者如果是B+树的话就是**大的在左,小的在右**。

所以,对于上面的那份原始数据:

4311d1111a8888h2222b5235e3322c7455g6644f

如果我们将这份数据按照`a desc`进行排序就是:

8888h7455g6644f5235e4311d3322c2222b1111a

非常简单吧,那如果我们将这份数据按照`b desc, c desc, d desc`排序就是:

8888h6644f7455g3322c4311d5235e2222b1111a

也非常简单,那如果我们要将这份数据按照`b desc, c asc, d desc`排序呢?这是不是就有点懵了?

其实不难,排序其实就是对数据比较大小,我们用下面三行数据来模拟一下:

3322c7455g4311d

首先,按照`b desc, c desc, d desc`来排序,得到结果如下:

7455g3322c4311d

按照`b desc, c asc, d desc`来排序,得到结果如下:

7455g4311d3322c

可能一部分大佬已经能理解,实际上`b desc`所表达的意思就是b字段数据大者在上,数据小者在下,数据相等的话则开始比较c字段,而c字段是按升序排的,也就是c字段数据小者在下,数据大者在上。所以就得到了上面的结果。

这就是降序索引

总结

实际上升序索引和降序索引是不同的排序方式而已,Mysql8中正在实现了降序索引后,我们在创建索引时更加灵活,可以根据业务需要的排序规则来创建合适的索引,这样能使你的查询更快。

当然本文只讲了原理,大家一定要知道Mysql中排序利用的B+树,而不是上面我举例的那种很简单的方式,但是就算用B+树原理也是一样的,比较数据的大小而已。还有一点,现在只有Innodb存储引擎支持降序索引。

MySQL面试题

Mysql 的技术特点是什么?

Mysql 数据库软件是一个客户端或服务器系统,其中包括:支持各种客户端程序和库的多线程 SQL 服务器、不同的后端、广泛的应用程序编程接口和管理工具。

Mysql 服务器默认端口是什么?

Mysql 服务器的默认端口是 3306。

与 Oracle 相比,Mysql 有什么优势?

Mysql 是开源软件,随时可用,无需付费。Mysql 是便携式的

带有命令提示符的 GUI。

使用 Mysql 查询浏览器支持管理

区分 CHAR_LENGTH 和 LENGTH?

CHAR_LENGTH 是字符数,而 LENGTH 是字节数。Latin 字符的这两个数据是相同的,但是对于 Unicode 和其他编码,它们是不同的。

在 Mysql 中 ENUM 的用法是什么?

ENUM 是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用。

Create table size(name ENUM('Smail,'Medium','Large');

Mysql 驱动程序是什么?

以下是 Mysql 中可用的驱动程序:

PHP 驱动程序

JDBC 驱动程序

ODBC 驱动程序

CWRAPPER

PYTHON 驱动程序

PERL 驱动程序RUBY

驱动程序CAP11PHP

驱动程序Ado.net5.mxj

TIMESTAMP 在 UPDATE CURRENT_TIMESTAMP 数据类型上做什么?

创建表时 TIMESTAMP 列用 Zero 更新。只要表中的其他字段发生更改,UPDATE CURRENT_TIMESTAMP 修饰符就将时间戳字段更新为当前时间。

主键和候选键有什么区别?

表格的每一行都由主键唯一标识,一个表只有一个主键。

主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键引用。

如何在 Unix 和 Mysql 时间戳之间进行转换?

UNIX_TIMESTAMP 是从 Mysql 时间戳转换为 Unix 时间戳的命令FROM_UNIXTIME 是从 Unix 时间戳转换为 Mysql 时间戳的命令

如何输入字符为十六进制数字?

如果想输入字符为十六进制数字,可以输入带有单引号的十六进制数字和前缀(X),或者只用(Ox)前缀输入十六进制数字。

如果表达式上下文是字符串,则十六进制数字串将自动转换为字符串。

如何显示前 50 行?

在 Mysql 中,使用以下代码查询显示前 50 行:SELECT*FROM

LIMIT 0,50;

可以使用多少列创建索引?

任何标准表最多可以创建 16 个索引列。

Mysql 表中允许有多少个 TRIGGERS?

在 Mysql 表中允许有六个触发器,如下:

BEFORE INSERT

AFTER INSERT

BEFORE UPDATE

AFTER UPDATE

BEFORE DELETE

AFTER DELETE

什么样的对象可以使用 CREATE 语句创建?

以下对象是使用 CREATE 语句创建的:

DATABASE

EVENT

FUNCTION

INDEX

PROCEDURE

TABLE

TRIGGER

USER

VIEW

什么是非标准字符串类型?

以下是非标准字符串类型:

TINYTEXT

TEXT

MEDIUMTEXT

LONGTEXT

MYSQL 数据表在什么情况下容易损坏?

服务器突然断电导致数据文件损坏。

强制关机,没有先关闭 mysql 服务等

mysql 有关权限的表都有哪几个?

Mysql 服务器通过权限表来控制用户对数据库的访问,权限表存放在 mysql 数据库里,由mysql_install_db 脚本初始化。这些权限表分别 user,db,table_priv,columns_priv 和host。

Mysql 中有哪几种锁?

MyISAM 支持表锁,InnoDB 支持表锁和行锁,默认为行锁

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低

行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高

小编也整理了一些MySQL资料需要的同学可关注微信公众号“老周扯IT”领取!

阿里面试官让我谈谈:Mysql中的降序索引底层实现,附20道面试题

展开阅读全文

页面更新:2024-04-20

标签:索引   升序   降序   数列   阿里   字段   底层   驱动程序   语法   速度   方式   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top