索引是什么?
??MySQL中的索引也是一種為了便于查找數據而在數據之外創建的一種數據結構,通過這種數據結構我們可以方便得根據條件查找我們想要得數據,索引的目的是加快數據的查找速度,從而提升查詢的效率。索引的作用就類似于新畫字典中的拼音目錄,我們通過拼音可以快速的查找到指定的字。換句話說,如果給你一部沒有拼音目錄的字典,那么我們只能在字典中一頁一頁的去翻(當然,如果字典中的每個字都是按拼音排序,咱也可以通過二分查找來實現),總而言之就是查找效率會非常低下了。因此我們總結一下,索引有以下幾個特點:
優點
??1.加快數據查詢的速度和效率。(相當重要!!!)
缺點
??1.建立索引需要消耗額外的存儲空間。因為索引也是一種按照某種數據結構組織的數據,通過這些數據我們可以快速地定位到我們想要查找的數據。
??2.建立和維護索引需要消耗額外的時間。雖然索引可以提升數據查詢的效率,但是大量的索引的創建和維護的時間成本并不低。
??3.當對表中的數據進行增加、刪除、修改時,除了維護原始數據,索引也需要同時進行動態的維護,降低了數據的維護速度
創建索引的建議
??上面我們對索引的優缺點進行了簡單的分析,那么什么情況下需要創建索引?什么情況下又不適合創建索引呢?我們給出以下幾點建議:
??1. 對于數據體量較大且查詢頻率遠高于變更頻率的列,建議創建索引。
??2. 對于數據區分度不大的列不建議創建索引。比如用戶的性別,枚舉范圍較小的列。
??3. 對于需要頻繁變更(修改和刪除)的列,不建議創建索引。因為在頻繁變更的列上創建索引,會導致變更操作的效率變低。
??4. 數據體量不大或者查詢需求不高的的情況下,不建議創建索引。
??5. 索引需要根據查詢需求來確定,并且盡可能以最小范圍的方式進行創建,不建議對所有列創建索引。對于業務已經變更,需求不大的索引,需要及時drop。
MySQL存儲引擎概覽
??在詳細介紹MySQL索引原理之前,我們需要先簡單介紹一下MySQL的存儲引擎。存儲引擎是處理不同表類型的SQL操作的MySQL組件,目前InnoDB已經成為MySQL默認的存儲引擎,也是目前使用范圍最廣的存儲引擎,除此之外,我們可以使用SHOW ENGINES
命令來查看當前版本的MySQL所支持的存儲引擎,示例如下:
mysql> SHOW ENGINES
*************************** 1. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 2. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
*************************** 5. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 8. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 9. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
??由于很多存儲引擎只針對特定的場景,很多人可能終其一生也不會用到,下面就從官網扒拉來一份幾種常見的MySQL特性對比,如下表所示:
Feature | MyISAM | Memory | InnoDB | Archive | NDB |
---|---|---|---|---|---|
B-tree indexes | Yes | Yes | Yes | No | No |
Backup/point-in-time recovery | Yes | Yes | Yes | Yes | Yes |
Cluster database support | No | No | No | No | Yes |
Clustered indexes | No | No | Yes | No | No |
Compressed data | Yes | No | Yes | Yes | No |
Data caches | No | N/A | Yes | No | Yes |
Encrypted data | Yes | Yes | Yes | Yes | Yes |
Foreign key support | No | No | Yes | No | Yes |
Full-text search indexes | Yes | No | Yes | No | No |
Geospatial data type support | Yes | No | Yes | Yes | Yes |
Geospatial indexing support | Yes | No | Yes | No | No |
Hash indexes | No | Yes | No | No | Yes |
Index caches | Yes | N/A | Yes | No | Yes |
Locking granularity | Table | Table | Row | Row | Row |
MVCC | No | No | Yes | No | No |
Replication support | Yes | Limited | Yes | Yes | Yes |
Storage limits | 256TB | RAM | 64TB | None | 384EB |
T-tree indexes | No | No | No | No | Yes |
Transactions | No | No | Yes | No | Yes |
Update statistics for data dictionary | Yes | Yes | Yes | Yes | Yes |
備注:
??1.在服務器中實現,而不是在存儲引擎中。
??2.只有在使用壓縮行格式時,才支持壓縮的MyISAM表。使用MyISAM壓縮行格式的表是只讀??的。
??3.在服務器端通過加密功能來實現。
??4.在服務器端通過加密功能來實現;MySQL 5.7及以上版本支持靜態數據加密
??5.在MySQL集群NDB 7.3及更高版本中支持使用外鍵。
??6.在MySQL 5.6及更高版本中支持FULLTEXT索引可用。
??7.在MySQL 5.7及更高版本中支持geospatial 索引可用。
??8.InnoDB內部利用哈希索引實現自適應哈希索引特性。
MySQL索引的分類
??MySQL中的索引,從作用范圍上可以將其分成分單列索引和組合索引。單列索引即一個索引只包含單個列,一個表可以有多個單列索引。組合索引即一個索引包含多個列。這里我們不對單列索引和組合索引做過多介紹。我們主要從不同的用途出發歸納MySQL的索引分類,MySQL中的索引根據其具體的用途在邏輯上主要分成分為以下 3 類:
1.常規索引
??常規索引是 MySQL 中最基本的索引類型,它沒有任何特殊限制限制,其主要目的就是提升數據的查詢效率。常規索引又可以根據其約束和限制的嚴苛程度分為3種,分別是:普通索引、唯一索引和主鍵索引。
普通索引:普通索引允許在索引的列中插入重復值和空值。
唯一索引:唯一索引與普通索引的不同的是創建唯一性索引的目的不僅僅是為了提高訪問速度,同時還要避免數據出現重復。唯一索引的列值必須唯一,但是允許有空值。如果是組合索引,則這些列值的組合的值必須唯一(組合索引不要某個列的值必須唯一)。
主鍵索引:主鍵索引是一種特殊的唯一索引,該索引是專門為主鍵字段創建的索引,不允許值重復或者為空值。
2. 全文索引
??首先全文檢索并不是MySQL最擅長的任務之一,如果有巨大的全文檢索需求,建議使用專門的全文檢索引擎,如Solr和ES等。但是MySQL使用全文索引提供了對全文檢索的支持,全文索引主要用來查找文本中的關鍵字,只能在 CHAR、VARCHAR 或 TEXT 類型的列上創建。全文索引允許在索引列中插入重復值和空值。
3. 空間索引
??與全文索引類似,MySQL中的空間索引也是一種針對特定類型的數據和查詢需求創建的索引, 空間索引主要是對空間數據類型的字段建立的索引,如GIS中常用的坐標數據(經度、維度),創建空間索引的列必須將其聲明為 NOT NULL,空間索引主要用于地理空間數據類型 GEOMETRY,對于沒有這種空間數據處理任務的人來說,這類索引很少會用到。我們當初在一個時空網絡的項目中使用到了空間索引,在針對GPS數據查詢和坐標點距離排序這塊,空間索引有著常規索引無法比擬的優勢。
MySQL索引的實現原理
??上文中我們提供過,MySQL中的索引根據用途和場景不同,主要可以分成三種:常規索引、全文索引和空間索引。不同索引的實現原理不同,且在不同的存儲引擎上的實現方式也不盡相同。比如常規索引的在InnoDB上可以使用B-Tree索引的方式實現,也可以使用Hash索引的方式實現;全文索引可以使用倒排索引的方式來實現;空間索引可以基于R-Tree的方式來實現。這里我們主要針對MySQL中Hash和B-Tree索引的實現原理進行詳細的介紹。
Hash索引原理
??Hash索引也稱為哈希索引或散列索引。MySQL 目前在 MEMORY和NDB 存儲引擎中都支持支持該種類型的索引,其中,MEMORY 存儲引擎將 Hash當成默認索引。Hash索引不是基于樹形的數據結構查找數據,而是根據索引列對應的哈希值的方法獲取記錄所在的位置。Hash索引的原理很簡單,大致如下圖所示,主要是維護一個Hash函數,插入數據的時候對索引列的值進行Hash,得到HashCode后將該行數據存儲在指定位置;查詢數據的時候,也是同樣的操作,先對索引列的值進行Hash,得到HashCode后去到指定的位置讀取當前行的數據。Hash索引的最大優點是訪問速度快,但也存在下面的一些缺點:
??1. 使用Hash索引需要在查詢和建立索引的過程中進行Hash計算,Hash計算是一個比較耗時的操作,相對于 B-樹索引來說,建立哈希索引會耗費更多的時間。
??2. 由于Hash的無序性,無法使用 Hash索引進行排序和范圍查找。
??3. Hash索引只支持等值比較。
??4. Hash索引不支持鍵的部分匹配,因為Hash值是通過整個索引值計算得到的。
??5.隨著數據量的增大,Hash沖突的現象會越來越明顯,此時會出現明顯的性能下降現象。
B+Tree索引原理
B+Tree索引是目前MySQL中使用最廣的索引,MySQL中的B+Tree索引根據其實現方式的不同又可以分為聚集索引和非聚集索引。其中InnoDB存儲引擎中的B+Tree的實現即為聚集索引,聚集索引的B+Tree中的葉子節點存放的是整張表的行記錄數據。而非聚集索引與聚集索引的主要區別在于非聚集索引的葉子節點并不包含行記錄的全部數據,而是存儲相應行數據的主鍵,MySQL中的MyISAM存儲引擎中的B+樹的實現就是非聚集索引。這里主要針對InnoDB存儲引擎中的B+Tree實現原理進行展示,不同的存儲引擎中,B+樹的實現方式也不一樣。B+樹索引是一個典型的數據結構,其包含的組件主要有以下幾個:
根節點:一個 B+樹索引只有一個根節點,根節點位于樹的最頂端。
分支節點:包含的條目指向索引里其他的分支節點。
葉子節點:包含的條目直接指向表里的數據行。B+樹中葉子節點之間通過指針彼此相連。
??基于這種樹形數據結構,表中的每一行都會在索引上有一個對應值。因此,在表中進行數據查詢時,可以根據索引值一步一步定位到數據所在的行。
??B+樹索引可以進行全鍵值、鍵值范圍和鍵值前綴查詢,也可以對查詢結果進行 ORDER BY 排序。但 B+樹索引必須遵循左邊前綴原則,要考慮以下幾點約束:
查詢必須從索引的最左邊的列開始。
查詢不能跳過某一索引列,必須按照從左到右的順序進行匹配。
存儲引擎不能使用索引中范圍條件右邊的列。
MySQL索引優化建議
??這里給出一些MySQL的索引優化建議,僅供在使用MySQL中作為參考。
1.優先選擇唯一性索引,盡量選擇區分度高的列作為索引,可以更快速的通過該索引來確定某條記錄。
2.為經常作為查詢條件的字段建立索引,為經常需要排序、分組和聯合操作的字段建立索引。
3.限制索引的數目: 越多的索引,會使更新表變得很浪費時間;盡量在當前索引的基礎上擴展索引,盡量不要新建索引;刪除不再使用或者很少使用的索引。
4.盡量使用字段長度較短的列做索引,如果索引的值很長,那么查詢的速度會受到影響。
5.如果索引的值很長,盡量使用前綴來索引,比如like只有在‘%’不在最左邊的時候索引才會生效,也就是最左匹配原則。
6.最左前綴匹配原則,非常重要的原則。
7.索引列不能參與計算,保持列“干凈”:帶函數的查詢不參與索引。