高性能Mysql讀書筆記#第五章

創建高性能索引

5.1索引的基礎

B-樹索引

有效的查詢類型:
1、全值匹配。(包含索引的所有信息)
2、匹配最左前綴。(包含索引最左的屬性信息)
3、匹配列前綴。(滿足2)
4、匹配範圍值。(滿足2)
5、精確匹配某一列並範圍匹配另外一列。(滿足2)
6、只訪問索引的查詢:無需訪問數據行,只需訪問生成的索引(B+樹);

限制:
1、如果不是按照索引的最左列開始查找,則無法使用索引。
2、不能跳過索引中的列。比如索引(lastname,firstname,birthday),若使用lastname+birthday,其實僅使用了索引的第一列。
3、若查詢中某個列的範圍查詢,則其右邊所有列無法使用索引優化查詢

B-樹與B+樹的區別

1、B-樹結點上存儲了鍵值
2、B+樹葉子結點可能是單鏈表還是雙向鏈表的形式鏈接在一起,方便排序和查找範圍

B+ 樹的優點在於:
由於B+樹在內部節點上不包含數據信息,因此在內存頁中能夠存放更多的內部節點,也就是key。 數據存放的更加緊密,具有更好的空間局部性。因此訪問葉子節點上關聯的數據也具有更好的緩存命中率。
B+樹的葉子結點都是相鏈的,因此對整棵樹的遍歷只需要一次線性遍歷葉子結點即可。而且由於數據順序排列並且相連,所以便於區間查找和搜索。而B樹則需要進行每一層的遞歸遍歷。相鄰的元素可能在內存中不相鄰,所以緩存命中性沒有B+樹好。
但是B樹也有優點,其優點在於,由於B樹的每一個節點都包含key和value,因此經常訪問的元素可能離根節點更近,因此訪問也更迅速

哈希索引

哈希索引(hash index)基於哈希表實現,只有精確匹配索引所有列的查詢纔有效。對於每一行數據,存儲引擎都會對所有的索引列計算一個哈希碼(hash code),哈希碼是一個較小的值,並且不同鍵值的行計算出來的哈希碼也不一樣。哈希索引將所有的哈希碼存儲在索引中,同時在哈希表中保存指向每一個數據行的指針。
哈希索引自身只需要存儲對應的哈希值,所以索引的結構十分緊湊,這也讓哈希索引查找的速度非常快。

哈希索引的限制:

哈希索引只包含哈希值和行指針,而不存儲字段值,所以不能使用索引中的值來避免讀取行。
哈希索引數據並不是按照索引值順序排序的,所以也就無法用於排序
哈希索引也不支持部分索引列匹配查找,因爲哈希索引始終是使用索引列的全部內容來計算哈希值的。
哈希索引只支持等值比較查詢,包含IN、=、<=>(注意<>和<=>是不同的操作,<=>左值可以等於NULL,<>和=左值若等於NULL,則結果均爲控),也不支持任何的範圍查詢。
訪問哈希索引的數據非常快,除非有很多哈希衝突(不同的索引列值可能會有相同的哈希值)。當出現哈希衝突的時候,存儲引擎必須遍歷該哈希值對應的鏈表中的所有的行指針,逐行進行比較,直到找到所有符合條件的行。
如果哈希衝突很多的話,一些所有維護操作的代價也很高。例如,如果在某個選擇性很低的列上建立哈希索引,那麼當從表中刪除一行時,存儲引擎需要遍歷對應哈希值的鏈表中的每一行,找到並刪除對應行的引用,衝突越多,代價越大。

5.2索引的優點

1、索引大大減少了服務器需要掃描的數據量:存儲引擎不用進行全表掃描。
2、索引可以幫助服務器避免排序和臨時表:B樹索引內的數據已經排好了序。
3、索引可以將隨機I/O變爲順序I/O:B樹索引中相關數據行存儲在一個磁盤頁面中。

注意:索引並不總是會提升性能,只有當索引幫助存儲引擎快速查找到記錄帶來的好處大於其帶來的額外工作時,索引纔是有效的。對於非常小的表,大部分情況下簡單的全表掃描更高效,對於中到大型的表,索引的就非常有效。但是對於特大型的表,建立和使用索引的代價將隨之增加。

5.3高性能的索引策略

5.3.1獨立的列

獨立的列是指索引列不能是表達式的一部分,也不能是函數的參數。
例如,下面這個查詢無法使用actor_id列的索引:
select actor_id from sakila.actor where actor_id + 1 = 5;

5.3.2前綴索引和索引選擇性

索引的選擇性是指,不重複的索引值(也稱爲基數,cardinality)和數據表的記錄總數(#T)的比值,範圍從1/#T到1之間。索引的選擇性越高,則查詢的效率越高,因爲選擇性高的索引可以讓MySQL在查找時過濾掉更多的行。唯一索引的選擇性時1,這是最好的索引選擇性,性能也是最好的。
有些時候需要索引很長的字符列,這會讓索引變得大且慢。這種情況下通常可以索引索引列的開始部分字符,這樣可以大大節約索引空間,從而提高索引效率,但是這樣會降低索引的選擇性。
前綴索引是可以讓索引更小、更快的有效辦法。但是無法使用前綴索引做order by和group by操作,以及覆蓋掃描

5.3.3 多列索引

在多個列上建立獨立的單列索引大部分情況下並不能提高MySQL的查詢性能。MySQL5.0和更新版本引入了一種叫做索引合併(index merge)的策略(需要注意的是,索引合併如果使用不當會很容易造成慢查詢),一定程序上可以使用表上的多個單列索引來定位指定的行。更早版本的MySQL只能使用其中某一個單列索引,然而很多情況下沒有哪一個獨立的單列索引是非常有效的。
使用explain語句分析sql時,可以在Extra列中看到是否使用了index merge。索引合併有時候是一種優化的結果,但是實際上更多時候說明了表中索引建的很糟糕:
當出現服務器對多個索引做相交操作時(通常有多個AND條件),通常意味着需要一個包含所有相關列的多列索引,而不是多個獨立的單列索引。
當服務器需要對多個索引做聯合操作時(通常有多個OR條件)通常需要耗費大量的CPU和內存資源在算法的緩存、排序和合並操作上。特別是當其中有些索引的選擇性不高,需要合併掃描返回的大量數據的時候。
優化器不會將這些計算到查詢成本中,優化器只關心隨機頁面讀取。這會使得查詢的成本被低估,導致該執行計劃還不如直接走全表掃描。這樣做不但會消耗更多的CPU和內存資源,還可能會影響查詢的併發性,但如果是單獨運行這樣的查詢則往往會忽略對併發性的影響。
如果在explain中看到有索引合併,應該好好檢查一下查詢和表的結構,看是不是已經是最優的。也可以通過參數optimization switch來關閉索引合併功能。也可以使用ignore index提示讓優化器忽略掉某些索引。

5.3.4 選擇合適的索引列順序

在如何選擇索引的列順序有一個經驗法則:將選擇性最高的列放在索引的最前面。這個經驗法則在某些時候有用,但通常不如避免隨機I/O和排序那麼重要。場景不同則選擇不同,沒有一個放之四海而皆準的法則。但是當不需要考慮排序和分組的情況下,將選擇性最高的列放在前面通常是很好的。

5.3.5 聚集索引(聚簇索引)

聚集索引並不是一種單獨的索引類型,而是一種數據存儲方式。在Oracle中也叫做索引組織表(index organized table)。和聚集索引相對於的叫非聚集索引,在Oracle中也叫堆組織表(heap organized table)。當表有聚集索引時,他的數據行實際上存放在索引的葉子頁。《高性能MySQL》中術語“聚集”,就是表示數據行和相鄰的鍵值緊湊地存儲在一起。說的通俗一點,就是數據行在磁盤上是按照索引順序存放在一起,當然這只是定義,實際中例如Innodb存儲引擎,只聚集在同一個磁盤頁面中的記錄,包含相鄰鍵值的頁面可能相距很遠。也就是說Innodb中,同一個磁盤頁面中的記錄是因爲在同一個頁面中,所以是存儲在一起的,但是邏輯相鄰的磁盤頁面由鏈表連接,實際上可能物理上相隔很遠。因爲無法同時把數據行存放在兩個不同的地方,所以一個表只能有一個聚集索引。
以下以Innodb存儲引擎做說明。到目前爲止,Innodb存儲引擎並不支持選擇哪個索引作爲聚集索引,在定義了主鍵的情況下,在Innodb中將通過主鍵聚集數據,如果沒有定義主鍵,Innodb會選擇一個唯一的非空索引代替。如果沒有這樣的索引,Innodb會隱式定義一個主鍵來作爲聚集索引。

聚集索引的優點:

1、可以把相關數據保存在一起。
2、數據訪問更快
3、使用聚集索引掃描的查詢可以直接使用葉節點中的主鍵值。

聚集索引缺點:

聚集數據能最大限度地提高了I/O密集型應用的性能,但如果數據全部都存放在內存中,則訪問的順序就沒有那麼重要了,聚集索引也就沒什麼優勢了。
插入速度嚴重依賴於插入順序。按照主鍵的順序插入是加載數據到Innodb表中速度最快的方式(所以在Innodb存儲引擎中,主鍵不推薦使用UUID,這是因爲UUID型主鍵會造成大量的隨機I/O操作,推薦使用和數據行沒有關係的auto increment整形主鍵是因爲整形存儲空間比較少,而且插入數據時,都是按照主鍵順序插入,速度會比較快)。
更新聚集索引列的代價會很高,因爲會強制Innodb將每個被更新的行移動到新的位置。
基於聚集索引的表在插入新行,或者主鍵被更新導致需要移動行的時候,可能面臨頁分裂的問題。所謂的頁分裂問題就是指當行的主鍵值要求必須將這一行插入到某個已滿的磁盤頁中時,存儲引擎會將該頁分裂成兩個頁面來容納該行。頁分裂會導致表佔用更多的磁盤空間以及爲了維護B+樹索引移動元素導致的開銷。
非聚集索引的葉子結點中包含了對應數據行的主鍵列。這可能會導致非聚集索引佔用比較大的空間。
非聚集索引訪問需要兩次索引查詢,而不是一次。這是因爲非聚集索引保存的行指針並不是指向數據行的物理位置的指針,而是行的主鍵值。這也就意味着通過非聚集索引查找行時,存儲引擎需要找到非聚集索引的葉子結點獲取對應的主鍵值,然後根據這個值去聚集索引中查找對應的行。在MySQL中之所以這樣設計是爲了避免數據行因爲更新、插入等操作導致數據行需要移動時也同時需要維護非聚集索引。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章