MySQL索引與優化
概念
索引儲存在記憶體中,為伺服器儲存引擎為了快速找到記錄的一種資料結構。
基本操作
為資料表新增索引:
ALTER TABLE table_name ADD INDEX index_name (column_list) //普通索引
ALTER TABLE table_name ADD UNIQUE (column_list) //唯一性索引,設定後,不允許插入重複值
ALTER TABLE table_name ADD PRIMARY KEY (column_list) //唯一索引,通常用於自增主鍵。
刪除索引
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY
檢視索引
SHOW INDEX FROM tblname;
SHOW KEYS FROM tblname;
優缺點及使用場景
減少表的檢索行數,提高查詢效率
建立唯一索引或者主鍵索引,保證資料欄位的唯一性
檢索時有分組和排序需求時,減少伺服器排序的時間
缺點:
建立和維護索引需要消耗時間及記憶體,隨著資料的增加而增加
索引欄位過多,資料量巨大時,索引佔據空間可能比表更大。
當對錶的資料進行更新操作時,索引也要動態的維護,這樣就會降低資料的維護速度。
使用注意:
表資料較小時不建議使用,此時全表掃描可能效率更好。
在經常需要where、排序、分組、取區間的列上建議使用。
列不能作為表示式的一部分,或者用作函式引數,否則失效。
當表更新操作遠大於select操作時,不建議新增索引。
索引底層資料結構瞭解
B樹
平衡多路查詢樹,一棵m階的B樹。
特性:
樹中每個結點最多含有m個孩子( m >= 2 );
除根結點和葉子結點外,其他每個結點至少 m/2 個孩子。
若根結點不是葉子,至少2個孩子。
有 j 個孩子的非葉節點恰好有 j-1 個關鍵碼,關鍵碼按遞增次序排序。
B樹存在磁碟中,我們想要查詢29,查詢過程:
1. 根據根結點找到檔案目錄的根磁碟塊1,將其中資訊匯入記憶體。 【磁碟IO操作一次】
2. 此時記憶體中有兩個檔案17,35和三個儲存其他磁碟頁面地址的資料。 比較:17<29<35,因此我們訪問指標P2
3. 根據P2指標,我們定位到磁碟3,並將其資訊匯入記憶體。【磁碟IO操作2次】
4. 此時記憶體中有兩個檔案26,30和三個儲存其他磁碟頁面地址資訊的指標,26<29<30,因此我們找到P2指標。
5. 根據P2指標,定位到磁碟8,將其中資訊匯入記憶體。【磁碟IO操作3次】
B+
相對B樹的不同特性:
非葉子節點的值會以最大或最小值出現在其子節點中,即葉子節點包含所有元素。
非葉子節點帶有索引資料和指向葉子節點的指標,不包含指向實際元素資料的地址資訊。僅葉子節點有所有元素資訊。
每個元素不儲存資料,只儲存索引值即主鍵。
所有葉子節點形成一個有序連結串列。
單行查詢時與B樹相同
範圍查詢時,比如查詢大於3小於8的資料,根據單行查詢方式查詢到3之後,通過連結串列直接遍歷後面的元素。
B+樹優勢:
B+樹的磁碟讀寫代價更低。同樣的一塊磁碟大小,B樹需要儲存表元素資料,B+只需要儲存索引,可以儲存更多節點。同等元素資料量下,B+樹層數更少。
B+樹的查詢效率穩定。因為非終結點只是關鍵字的索引,所以任何關鍵字的查詢必須走一條根到葉子的路。
B+樹中葉子結點也成一個連結串列,所以B+樹在面對範圍查詢時比B樹更加高效。
InnoDB索引使用
索引分主索引和輔助索引
主索引在表建立後即存在。以主鍵為索引,葉子節點儲存元素資料。
為主鍵外的欄位新增的索引為輔助索引。以欄位內容為索引,葉子節點儲存元素對應主鍵。
MyISAM不同點在於葉子儲存的不是元素資料,而是元素資料地址。實現索引與實際資料分離。
如何高效率使用索引
獨立列查詢
SQL語句使用不當時,將無法使用現存索引而去全表掃描。所以需要注意:索引列不能是表示式的一部分,也不能是函式的引數。
通過在查詢SQL前加explain,檢視是否有使用索引。
上圖中,為timestamp欄位添加了索引。 明顯使用DATE()函式後,timestamp不使用索引,rows行數為總資料行數。
字首索引查詢(注意選擇性把握)
選擇性指不重複的索引值和資料表的記錄總數的比值。選擇性最高時,即所有鍵不重複時選擇性為1。
由上面對索引內部實現的描述我們得知,我們索引的欄位越長時,所佔記憶體也就越大。字首索引意在保持較高選擇性的情況下,取欄位的字首部分用於索引,降低記憶體使用率。
我對測試表中pdl欄位及字首部分的選擇性進行觀測如下:
如圖,字首為9時選擇性已經較高,再增加時,沒有明顯提升。這時,如果pdl欄位很長,就可以考慮使用pdl的字首9個字元作為字首索引。
alter table com_pdl_stat add key left_pdl
(pdl(9));
1
注意:無法使用字首索引做ORDER BY 和 GROUP BY,考慮業務場景做取捨。
多列索引合併
很多時候我們為了查詢方便,為很多列單獨建立索引。但我們在使用where篩選時,卻多使用AND,OR等條件。
當我為表的pdl,timestamp欄位單獨設定索引時,and查詢為:
通過key標誌知道此時僅使用了pdl欄位的索引。filtered僅17.92.
這裡的僅使用了pdl欄位索引。(高效能提到5.0之後的版本會各自使用pdl和timestamp欄位,然後SQL伺服器對多個索引結果做相交(AND)或聯合操作(OR)操作,通過extra可查詢,但是我的5.7沒有這種優化,不知道為什麼~~)
如上,僅使用where條件的第一個欄位索引 或者 伺服器消耗CPU,記憶體等資源去做合併工作,都會影響查詢效能。
這是有必要合併索引,建立pdl_time(pdl, timestamp)索引後同樣的查詢結果如下:
pdl_time索引被使用,filtered達到100%。
在建立多列索引時注意:
- 通常將選擇性高的欄位放在前面
- 多列欄位的字首也可以作為索引(例如(a,b)索引時,可以單獨使用a索引,但不能單獨使用b索引)
聚簇索引
聚簇索引指的是一種資料組織結構。判斷標準為:索引的葉子節點中,儲存的是資料還是隻想資料塊的指標。如果是指向資料塊指標,則為非聚簇索引。
索引型別依賴儲存引擎,Innodb使用的是聚簇索引,MyISAM使用非聚簇索引
Innodb主鍵索引圖:
如圖為Innodb儲存引擎生成的主鍵索引結構。非葉子節點儲存主鍵,葉子節點儲存主鍵和行資料(還有事務ID和回滾指標)。
Innodb輔助索引圖:
如圖為Innodb儲存引擎生成的輔助索引結構。葉子節點儲存索引欄位和對應的主鍵值,索引到主鍵值後,根據主鍵值再去主鍵索引中查詢對應的資料。
優點在於:
減少磁碟IO次數。使用索引查詢資料時,索引節點和資料被一起載入記憶體,不需要根據指標再進行一次IO讀取。
無需維護輔助索引。當出現數據頁分裂時,無需更新索引中的資料塊指標。
非聚簇索引圖:
非聚簇索引主鍵索引和輔助索引結構一致。
瀋陽性病醫院哪家好:http://yyk.39.net/sy/zhuanke/fc844.html
瀋陽治療溼疣正規醫院:http://yyk.familydoctor.com.cn/20631/