MySQL 8 新特性之降序索引底層實現

什麼是降序索引

你們可能對索引比較熟悉,而對降序索引比較陌生,事實上降序索引是索引的子集。mysql

咱們一般使用下面的語句來建立一個索引:算法

create index idx_t1_bcd on t1(b,c,d);
複製代碼

上面sql的意思是在t1表中,針對b,c,d三個字段建立一個聯合索引。sql

可是你們不知道的是,上面這個sql實際上和下面的這個sql是等價的:數組

create index idx_t1_bcd on t1(b asc,c asc,d asc);
複製代碼

asc表示的是升序,使用這種語法建立出來的索引叫作升序索引。也就是咱們平時在建立索引的時候,建立的都是升序索引。bash

可能你會想到,在建立的索引的時候,能夠針對字段設置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以前僅僅只是語法層面的支持,底層並無真正支持。學習

咱們分別使用Mysql七、Mysql8兩個版原本舉例子說明一下:ui

在Mysql七、Mysql8中分別建立一個表,有a,b,c,d,e五個字段:spa

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中你將獲得結果:

image.png

Mysql8中你將獲得結果:

image.png

咱們只關心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');
複製代碼

那麼這些數據確定是存儲在文件中的,因此文件中保存這些數據的格式大概以下,順序與插入順序保持一致:

4311d
1111a
8888h
2222b
5235e
3322c
7455g
6644f
複製代碼

注意,t1是Innodb的存儲引擎,並且a字段是主鍵,因此Innodb存儲引擎在處理這些插入的數據時,會按主鍵進行排序,也就是上面我說的文件中保存這些數據的格式是不許確的,由於不想篇幅太長,因此不去深究,感興趣的同窗能夠關注一波公衆號:1點25,我會專門寫一篇文章來說解Innodb中索引的具體實現,包括B+樹究竟是如何生成的。

而若是咱們基於上面的這種存儲方式,來查找數據,好比查找a=3的這行記錄,查找須要從第一行記錄開始查找,那麼要查找6次,而若是咱們將上面的數據按照a字段的大小來進行排序:

1111a
2222b
3322c
4311d
5235e
6644f
7455g
8888h
複製代碼

排好序以後,若是咱們仍是查找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三個字段進行排序,那麼排序以後相似:

1111a
2222b
5235e
4311d
3322c
7455g
6644f
8888h
複製代碼

能夠好好看下,上面的記錄是按照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+樹了,仍是同樣,由於篇幅不想太長,感興趣的同窗能夠關注一波公衆號:1點25,我會專門寫一篇文章來說解Innodb中索引的具體實現,包括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+樹的話就是大的在左,小的在右

因此,對於上面的那份原始數據:

4311d
1111a
8888h
2222b
5235e
3322c
7455g
6644f
複製代碼

若是咱們將這份數據按照a desc進行排序就是:

8888h
7455g
6644f
5235e
4311d
3322c
2222b
1111a
複製代碼

很是簡單吧,那若是咱們將這份數據按照b desc, c desc, d desc排序就是:

8888h
6644f
7455g
3322c
4311d
5235e
2222b
1111a
複製代碼

也很是簡單,那若是咱們要將這份數據按照b desc, c asc, d desc排序呢?這是否是就有點懵了?

其實不難,排序其實就是對數據比較大小,咱們用下面三行數據來模擬一下:

3322c
7455g
4311d
複製代碼

首先,按照b desc, c desc, d desc來排序,獲得結果以下:

7455g
3322c
4311d
複製代碼

按照b desc, c asc, d desc來排序,獲得結果以下:

7455g
4311d
3322c
複製代碼

可能一部分大佬已經能理解,實際上b desc所表達的意思就是b字段數據大者在上,數據小者在下,數據相等的話則開始比較c字段,而c字段是按升序排的,也就是c字段數據小者在下,數據大者在上。因此就獲得了上面的結果。

這就是降序索引

總結

實際上升序索引和降序索引是不一樣的排序方式而已,Mysql8中正在實現了降序索引後,咱們在建立索引時更加靈活,能夠根據業務須要的排序規則來建立合適的索引,這樣能使你的查詢更快。

固然本文只講了原理,你們必定要知道Mysql中排序利用的B+樹,而不是上面我舉例的那種很簡單的方式,可是就算用B+樹原理也是同樣的,比較數據的大小而已。

還有一點,如今只有Innodb存儲引擎支持降序索引

若是以爲這篇文章能讓你學到知識,可否幫忙轉發,將知識分享出去。 若是想第一時間學習更多的精彩的內容,請關注微信公衆號:1點25

相關文章
相關標籤/搜索