談談MySQL的索引

索引

前言

總所周知,資料庫查詢是資料庫的最主要功能之一。我們都希望查詢數據的速度能儘可能的快。而支撐這一快速的背後就是索引;MySQL索引問題也是大家經常遇到的面試題模組,想想自己也沒有去系統地總結過索引,所以記錄這篇文章來講下索引。下面還是按照是什麼->有什麼用->怎麼用->來寫

是什麼

往往大家第一時間提到索引,可能就會說到它是一種數據結構,來提高查詢效率的數據結構,用在常用來查詢的欄位上。但是原理是什麼呢?為什麼它就可以加快查詢?

首先,現如今,資料庫系統大多的索引底層結構是B樹或者B+樹,在數據結構的學習中,大家可能都有了解過,我們先簡單介紹下這兩種結構。

B樹

  1. 特點:每個結點都有數據,同時還有指向其下子樹的指針域,單個結構和鏈表的基本單元相似。
    1. 每個結點一個數據,等於就命中,小於該數據走左邊,大於走右邊

image.png

B+樹

  1. 是B樹的變形,多路搜索樹,是一種稠密索引
  2. 特點:真實的數據存儲在葉子結點的鏈表中,其他非葉子結點並沒有數據,而是作為葉子結點的索引;鏈表中的關鍵字是有序的。所有葉子結點都在同一層

image.png

B樹和B+樹結構上異同

同:都是平衡樹,每個結點到葉子結點的高度都是相同的,也保證每個查詢都是穩定,查詢的時間複雜度是log2(n),利用平衡樹的優勢是可以很大程度加快查詢的穩定性的。

異:關鍵字數量不同,存儲的位置也不同,查詢不同;B樹在找到具體的數值以後,則結束,B+樹通過索引找到葉子結點的數據才結束,也就是B+樹一定都得找到葉子結點。

有什麼用

對於兩種樹結構的使用和應用總結,也就是重要作用。

B樹的樹記憶體儲數據,因此查詢單條數據的時候,B樹的查詢效率不固定,最好的情況是O(1)。我們可以認為在做單一數據查詢的時候,使用B樹平均性能更好。但是,由於B樹中各節點之間沒有指針相鄰,因此B樹不適合做一些數據遍歷操作。

B+樹的數據只出現在葉子節點上,因此在查詢單條數據的時候,查詢速度非常穩定。因此,在做單一數據的查詢上,其平均性能並不如B樹。但是,B+樹的葉子節點上有指針進行相連,因此在做數據遍歷的時候,只需要對葉子節點進行遍歷即可,這個特性使得B+樹非常適合做範圍查詢。

接下來重點講的是MySQL的索引結構。

講回索引,在MySQnL中,索引屬於存儲引擎級別的概念,而我們常常提到MySQL的引擎,就會提到MyISAM和InnoDB。這裡插一下,MyISAM是非聚集(也叫非聚簇)索引,而InnoDB是聚集索引(也叫聚簇)。其實更簡單通俗得講,正文內容按照一個特定維度排序存儲,這個特定的維度就是聚集索引;

聚集索引是指資料庫錶行中數據的物理順序與鍵值的邏輯(索引)順序相同。一個表只能有一個聚集索引,因為一個表的物理順序只有一種情況,所以,對應的聚集索引只能有一個。如果某索引不是聚集索引,則表中的行物理順序與索引順序不匹配,與非聚集索引相比,聚集索引有著更快的檢索速度。 –《百度百科》

MyISAM引擎使用B+Tree作為索引結構,葉節點的data域存放的是數據記錄的地址,想要獲得數據,還得通過地址去獲得;同時非聚集索引索引項順序存儲,但索引項對應的內容卻是隨機存儲的;

InnoDB表數據文件本身就是一個索引結構,樹的葉節點data域保存了完整的數據記錄,這種索引叫做聚集索引。這種索引特點是葉子結點完全包含了數據,同時InnoDB要求按主鍵聚集,所以也要求表要有主鍵,沒有的話系統會自動選擇一個唯一標識數據記錄的列作為主鍵。因此,InnoDB的表也叫做索引表;

最後借用一個解釋來幫助大家理解聚集索引和非聚集索引。同時這裡有個很好的例子

漢語字典提供了兩類檢索漢字的方式,第一類是拼音檢索(前提是知道該漢字讀音),比如拼音為cheng的漢字排在拼音chang的漢字後面,根據拼音找到對應漢字的頁碼(因為按拼音排序,二分查找很快就能定位),這就是我們通常所說的字典序;第二類是部首筆畫檢索,根據筆畫找到對應漢字,查到漢字對應的頁碼。拼音檢索就是聚集索引,因為存儲的記錄(資料庫中是行數據、字典中是漢字的詳情記錄)是按照該索引排序的;筆畫索引,雖然筆畫相同的字在筆畫索引中相鄰,但是實際存儲頁碼卻不相鄰。

怎麼用

首先講下sql語句。

# 主要記住加索引和刪索引操作
# 可以在一開始建表時候加,也可以後面加
# ALTER TABLE用來創建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADD INDEX index_name (column_list);

# CREATE INDEX可對錶增加普通索引或UNIQUE索引。
CREATE INDEX index_name ON table_name (column_list)
# 刪除
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
# 這個只在刪除主鍵的時候使用 常常一張表只有一個主鍵
ALTER TABLE table_name DROP PRIMARY KEY

下面的是簡單使用情況以及結果分析(有索引和沒索引的分析),先看一開始表結構的索引情況

image.png

執行以下語句,建立一個first_name_last_name索引。

USE myemployees;
SHOW TABLES;
DESC employees;
# 建立了二級索引,是一個聯合索引
ALTER TABLE employees ADD INDEX first_name_last_name
(first_name, last_name);
# 為了明確看到查詢性能,我們啟用profiling並關閉query cache:
SET profiling = 1;
SET query_cache_type = 0;
SET GLOBAL query_cache_size = 0;
# 用EXPLAIN來查看sql語句執行的情況
EXPLAIN SELECT * from employees WHERE first_name='Alyssa' AND last_name LIKE '%on';

DESC employees;
# 刪除索引
DROP INDEX first_name_last_name ON employees;

# 查看無索引狀態下的執行效率
SELECT * from employees WHERE first_name='Alyssa' AND last_name LIKE '%on';

查看此時的索引結構,以及有了索引

image.png

執行查詢sql,看看有無索引的情況下的EXPLAIN語句情況

首先是無索引下的結果

image.png

再來是有索引的

image.png

這裡解釋下我標註出來的這三個參數,其實這裡的數據量不是很大,看查詢時間差距不大,所以查看rows的參數便可以參考下兩個查詢的區別,一個只需一行,另一個走了107行數據。所以說索引加快查詢效率。之所以會有快速的效果,就是由於上面的B+樹的數據結構在起作用。

就像十億個數據,如果按照常規邏輯,可能最差的情況下,需要匹配十億次才可以找到,加上這十億個數據給記憶體帶來了多少的負荷可想而知,所以要是轉化為平衡樹,可能只需要十層或者十幾層之類的樹結構,也就數據只需要花費很少的IO開銷就可以找到了。這兩個的差別就是天壤之別了。

type:表示MySQL在表中找到所需行的方式

​ ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行

​ ref::表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值

ROWS: 表示MySQL根據表統計資訊及索引選用情況,估算的找到所需的記錄所需要讀取的行數

**Extra:****該列包含MySQL解決查詢的詳細資訊 **

最後

借鑒1

借鑒2