是什么
索引用於快速的查詢某些特殊列的某些行。如果沒有索引, MySQL 必須從第一行開始,然后通過搜索整個表來查詢有關的行。表越大,查詢的成本越大。如果表有了索引的話,那么 MySQL 可以很快的確定數據的位置,而不用查詢整個表格。這比順序的讀取每一行要快的多。索引就像我們查字典時的目錄一樣,我們通過查詢字典的目錄,可以定位到某一行數據。
大多數的 MySQL 的索引(主鍵索引,唯一索引,普通索引,全文索引)都是 B-trees 結構。例外的情況有:在空間數據類型使用 R-trees 結構。存儲引擎為 MEMORY 的數據庫,也可以支持哈希索引。InnoDB 存儲引擎的全文索引使用反向列表結構。
使用場景
MySQL 會使用到索引的場景如下:
1.根據一個條件快速的匹配到對應的行。
2.縮小查詢影響行數。如果一個查詢字段有多個索引,MySQL 通常選擇使用影響行數最小的索引(選擇性最高的索引)。索引的選擇性的計算 select count(distinct name) / count(*) from table;
3.對於組合索引,索引左邊的列可以用索引前綴優化器來查詢數據。例如,你有個三列的組合索引(col1,col2,col3) ,那么你可以使用索引查詢(col1),(col1,col2),(col1,col2,col3)這三種組合的數據。有關於組合索引,詳細請看另外一篇博客 MySQL 組合索引
4.當和其他表進行連表查詢的時候,如果進行判斷的列的數據類型和大小相同,那么再這兩個列上使用索引,可以讓判斷更加效率。例如:在如下查詢中,給tb1.name和tb2.name添加索引會提升查詢效率。 SELECT * FROM tb1, tb2 WHERE tb1. name = tb2. name
在這里,VARCHAR 與 CHAR 被認為是相同的類型。需要注意的是,如果要讓索引生效,不僅需要類型一致,大小也必須一致。例如,VARCHAR(10) 和 CHAR(10) 大小相同可以使用索引,但 VARCHAR(10) 與 CHAR(15)就無法使用索引。
5.查找索引列的 MIN() 或 MAX()值。
6.通過索引列進行排序或分組,或者組合索引的左前綴進行排序或分組。
7.查詢索引列的內容。(如果只需要返回索引列的值,那么不需要查詢數據行,直接從內存中讀取檢索值。這種情況稱為覆蓋索引)例如: SELECT key_part FROM table WHERE key_part=1
對於小型表或報表查詢處理大多數或所有行的大型表的查詢,索引不太重要。當查詢需要訪問大多數行時,順序讀取比通過索引更快。順序讀取可以最大限度地減少磁盤搜索,即使查詢不需要所有行也是如此。只有數據較大,並且需要訪問其中一部分數據的時候,索引才會顯得比較重要。
怎么用
查看索引
SHOW INDEX FROM table
運行后,顯示結果如下:

其中,各個字段的含義:
table: 表的名稱
Non_unique: 索引是否可以重復。不可以重復則為0;可以重復則為1。
Key_name: 索引名稱。創建的時候,可以選擇輸入,不輸入 MySQL 自動生成。如果索引是主鍵,則名稱始終為 PRIMARY。
Seq_in_index: 索引中的列序列號,從1開始。
Column_name: 索引涉及到的列的名稱。
Collation:列如何在索引中排序。這可以具有值 A(ascending 升序),D ( descending 降序)或NULL(未排序)。
Cardinality: 索引中唯一值的數量(不是實時更新的准確數據)。
Sub_part: 索引前綴長度。如果使用字段的部分字符作為索引,那么顯示索引字符數量。如果使用整個字段都被索引,那么為 NULL。
Packed: key的打包方式,NULL 表示不打包。
Null: 索引列包含 NULL 或者 ‘’ 的時候,會是 YES。
Index_type: 索引類型。(BTREE, FULLTEXT,HASH, RTREE)之一。
Comment: 未在當前列中描述的索引信息,例如 disabled 索引是否已禁用。
Index_comment: 在創建索引時提供的注釋。
Visible: 索引是否對優化程序可見(有的版本會出現該信息)。
添加索引
CREATE INDEX index_name ON table_name (key_part,...)
ALTER TABLE t1 ADD INDEX index_name (key_part)
通常,在創建表時創建索引。對於InnoDB存儲引擎的表。其中主鍵確定數據的物理布局,可以向現有表中添加索引。key_part 表示組成索引的列的列名,如果是多個列名,那么將產生一個組合索引。在 key_part 參數后可以添加 ASC 或者 DESC 去指定索引按照正序排列還是倒序排列。
關於創建索引需要注意的是:
組合索引
組合索引是一個由多個列組成的索引。舉例說明:例如在表 address 中有三個字段,分別為 Provincial 省 city 市 county 縣 在建表的時候,用這三個字段組成一個組合索引。代碼如下:
1 CREATE TABLE address ( 2 provincial VARCHAR (10), 3 city VARCHAR (10), 4 county VARCHAR (10), 5 INDEX (provincial, city, county) 6 )
這里的索引是這樣創建的:首先按照省排序,然后,再根據同一個省的內容,按照市進行排序,最后,按照縣去排序。即,首先按照第一列進行索引排序,如果第一列內容一致,那么按照第二列進行排序,以此類推。
前綴索引
如果將字符串的列作為索引,可以創建前綴索引。一般情況下某個前綴的選擇性也是足夠高的,足以滿足查詢性能。對於BLOB,TEXT,或者很長的VARCHAR類型的列,必須使用前綴索引。前綴索引以字節為單位。前綴索引支持的長度取決於存儲引擎。例如,對於InnoDB 使用 REDUNDANT 或 COMPACT 行格式的表, 前綴最長可達767字節。對於InnoDB使用DYNAMIC 或 COMPRESSED 行格式的表, 前綴長度限制為3072字節 。對於MyISAM表,前綴長度限制為1000個字節。
如果指定的索引前綴超過最大列數據類型大小,對於非唯一索引,如果啟用了嚴格的SQL模式,創建會發生錯誤。如果未啟用嚴格SQL模式,索引長度減少到最大列數據類型大小,並產生警告。
創建前綴索引的長度,取決於索引的選擇性。詳見另外一篇博客:索引選擇性
創建前綴索引語法如下(這里的10 表示截取前10個字符):
CREATE INDEX key_part_name ON table_name (key_part(10));
ALTER TABLE table_name ADD INDEX index_name (key_part(10))
方法索引
這里的索引類型英文名稱為:Functional Key Parts 這里作者並不清楚官方的翻譯名稱為啥,只是根據索引的方式進行翻譯。如果不對,歡迎大神指正。
這個索引類似於兩個前綴索引的拼接。直接舉個例子就明白了:在 t1 表中有兩個列,col1 和 col2 我要創建一個包含完整的 col1 列和 col2 列的前10個字節組成一個組合索引。代碼如下:
CREATE TABLE t1 ( col1 VARCHAR(10), col2 VARCHAR(20), INDEX (col1, col2(10)) );
在 MySQL 8.0.13版本及更高版本中,MySQL 支持表達式進行索引。這里,需要將運算表達式寫在括號內進行縮印的聲明。例如:
1 -- 方法索引 2 CREATE TABLE t1 ( 3 col1 INT, 4 col2 INT, 5 INDEX func_index ((ABS(col1))) 6 ); 7 8 CREATE INDEX idx1 ON t1 ((col1 + col2)); 9 10 CREATE INDEX idx2 ON t1 ( 11 (col1 + col2), 12 (col1 - col2), 13 col1 14 ); 15 16 ALTER TABLE t1 ADD INDEX ((col1 * 40) DESC);
唯一索引
通過 UNIQUE 創建的索引。索引列的內容非null值的時候必須是唯一的,null值可以不唯一。如果添加重復值,則會發生錯誤。如果在創建唯一索引的時候指定前綴值,那么前綴必須是唯一的。創建語法: CREATE UNIQUE INDEX unique_index_name ON table_name (key_part)
全文索引
全文索引,顧名思義,支持全文檢索的索引。僅支持 Innodb 和 MyISAM 兩種存儲引擎。並且只能包括 CHAR, VARCHAR 和 TEXT 列,索引始終發生在整個列上,不支持前綴索引。(即使寫了也沒用)可以對字段進行全文檢索。對於數據量比較大的數據集,先將數據加載到沒有數據的表中,然后再添加索引,效率要比把數據直接向有索引的表中添加高。
空間索引
空間索引是為空間搜索提供一種合適的數據結構,以提高搜索速度。對於空間索引,作者研究並不多,這里大概介紹下空間索引的用處。等以后研究深刻后,再補上這部分內容。首先,空間索引是干什么用的?舉例:當我們需要按照某個點,查詢附近的50米內都有哪些客戶存在。對於這個需求,可能的解法如下:
1.我們可以根據用戶的經緯度,去計算每個人跟我們的當前點的距離,然后跟50米去作對比。這在客戶數據量少的時候,還可以這么做,數據量大的時候,將會特別的浪費性能。
2.先畫一個方框,把50米范圍的數據的經緯度畫出來,通過經緯度的值進行篩選后,得到一個正方形的區域,然后再進行計算。這時候,會少很多計算,但依然不是最優方案。
3.使用空間索引。將空間按照一定規則划分為不同的區域,在檢索的時候,根據設計的區域,取出相應的數據。空間索引結構圖如下(圖片來自知乎):

刪除索引
刪除索引沒啥好說的,語句如下:
DROP INDEX
如果索引所在的列刪除,那么該列對應的索引也會自動刪除。
索引優化
主鍵優化
表的主鍵是唯一且非空的索引,在使用InnoDB存儲引擎的時候,表數據直接掛載在主鍵的葉子節點上,是查詢速度最快的索引。
如果表的內容很多,並且很重要。但是沒有明顯的列和列的集合作為主鍵的話,可以單獨創建一個自動增長的值作為主鍵。當使用外鏈查詢的時候,這個id可以作為指向內容的指針。
外鍵優化
如果你的表有很多列,你可以將查詢頻率比較低的列拆分到其他表格,並通過復制id的方式讓它們與主表關聯。這樣,每個小表都會有個主鍵來快速查找其他數據。在查詢的時候,就可以僅查詢自己需要的列集。這時,查詢會執行較少的 I/O 並且占用較少的內存。整體原則是:為了提高性能,盡可能少的從磁盤讀取數據。這就是拆表的原則。

