《高效能MySQL》第5章 建立高效能的索引
5.1 索引基礎
索引是儲存引擎快速找到記錄的一種資料結構,因為在引擎層,所以沒有統一的標準。 如果沒有特別說明,一般的索引指B-Tree索引,InnoDB用的B+樹
不需要全表掃描,而是從索引根節點開始搜尋。 根節點的槽中存放指向子節點的指標。通過比較節點頁的值和要查詢的值可以找到合適的指標進入下層子節點,這些指標實際上定義了子節點頁中值的上限和下限。
葉子節點比較特別,他們的指標指向的是被索引的資料,而不是其他的節點頁。 樹的深度和表的大小直接相關。
前面所述的索引樹對如下型別的查詢有效
- 全值匹配:和索引中所有列進行匹配
- 匹配最左字首:只使用索引的第一列
- 匹配列字首:匹配某一列的值的開頭部分
- 匹配範圍值:比如匹配姓在Allen和Barrymore之間的人。這裡也只使用索引第一列
- 精確匹配某一列並範圍匹配另外一列:比如查詢姓張名三的人
- 只訪問索引的查詢
下面是B-Tree索引的限制:
- 如果不是按照索引的最左列開始查詢,則無法使用索引
- 不能跳過索引中的列:如果不指定名,則MySQL只能使用索引的第一列
- 如果查詢中有某個列的範圍查詢,則其右邊所有列都無法使用索引(LIKE是一個範圍條件查詢)
雜湊索引 基於雜湊表實現,只有精確匹配索引所有列的查詢才有效。 對於每一行資料,儲存引擎會對所有的索引列計算一個雜湊碼(代表物件的特徵,同一個類的物件按照自己的不同特徵儘量有不同的雜湊碼)。雜湊碼是一個較小的值,並且不同鍵值的行計算出來的雜湊碼也不一樣。雜湊索引將所有的雜湊碼存在索引中,同時在雜湊表中儲存指向每個資料行的指標。
在MySQL中,只有Memory引擎顯示支援雜湊索引。它同時支援B-Tree索引。值得一提的是,它支援非唯一雜湊索引。 先計算Peter的雜湊碼,然後找value即指向第N行的指標,最後判斷第N行值是否為Peter
- 雜湊索引查詢速度非常快,但它的限制是:
- 雜湊索引只包含雜湊值和行指標,而不儲存欄位值,所以不能使用索引中的值來避免讀取行。
- 雜湊索引資料不是按照索引值順序儲存的,所以就無法排序
- 雜湊索引也不支援部分索引列匹配查詢,雜湊索引始終是使用索引列的全部內容來計算雜湊值的。如資料列(A,B)上建立索引,如果查詢只有資料列A則無法使用索引
- 只支援等值比較查詢
- 出現雜湊衝突(不同索引列值有相同雜湊值)時,儲存引擎必須遍歷連結串列中所有行指標,逐行進行比較。
InnoDB引擎有一種特殊功能叫”自適應雜湊索引“,當索引值被頻繁使用時,它會在記憶體中基於B-Tree索引上再建立一個雜湊索引。
建立自定義雜湊索引 SELECT id FROM url WHERE url=”http://www.mysql.com” AND url_crc=CRC32(“http://www.mysql.com“) 這樣實現的缺陷是需要維護雜湊值,可以手動維護,也可以使用觸發器實現。 不要用SHA1和MD5作為雜湊函式,因為他們計算出來的雜湊值是非常長的字串,浪費大量空間。
一個簡單的辦法可以使用MD5()函式的返回值的一部分來作為自定義雜湊函式。這樣實現最簡單。
要避免衝突問題,必須在WHERE條件中帶入雜湊值和對應列值。
空間資料索引(R-Tree):會從所有維度索引資料 全文索引
5.2 索引的優點
- 大大減少了伺服器需要掃描的資料量
- 幫助伺服器避免排序和臨時表。
- 將隨機IO變為順序IO
5.3 獨立的列
查詢的列不是獨立的,就不會使用索引。 獨立的列是指索引列不能是表示式的一部分,也不能是函式的引數。
5.3.2 字首索引性和索引選擇性 索引選擇性指:不重複的索引值和資料的記錄總數的比值。索引的選擇性越高則查詢效率越高。
為了決定字首的合適長度,需要找到最常見的值的列表,然後和常見的字首列表進行比較。
計算合適的字首長度的另一個辦法是:計算完整列的選擇性,並使字首的選擇性接近於完整列的選擇性。
比如字首為4最常出現的城市的次數,看是不是基本均勻一致 會不會最常出現的字首的出現次數(可能只有三個字母)比最常出現的城市的出現次數大得多。
字首索引是能使索引更小,更快的有效方法,但缺點:MySQL無法用字首索引做ORDER BY和GROUP BY,也無法使用字首索引做覆蓋掃描。
字尾索引:可以把字串反轉後儲存,並基於此建立字首索引
5.3.3 多列索引 在多個列上建立獨立的索引大部分情況並不難提高Mysql的查詢效能。 在Mysql5.0後的版本,將結果進行合併,用OR條件的聯合(UNION),AND條件的相交(intersection)。
5.3.4 選擇合適的索引列順序
將選擇性最高的列放到索引最前列。通常不如避免隨機IO和排序那麼重要
5.3.5 聚簇索引
不是一種單獨的索引型別,而是一種資料儲存方式。它的資料行存放在索引的葉子頁中。聚簇表示資料行和相鄰的鍵值緊湊地儲存在一起。所以一個表只能頁一個聚簇索引。 因為是儲存引擎負責索引,不是所有的儲存引擎都支援聚簇索引。 索引列包含了整數值,葉子頁包含了行的全部資料。
如果沒有定義主鍵,InnoDB會選擇一個唯一的非空索引作主鍵,如果沒有這樣的索引,InnoDB會隱式定義一個主鍵作聚簇索引
優點:
- 將索引和資料儲存在同一個B-Tree中,訪問快
- 可以把相關資料儲存在一起,例如使用者郵箱,根據使用者ID來聚集資料
- 覆蓋索引掃描的查詢可以直接使用頁節點的主鍵值
缺點:
- 資料全放在記憶體裡,順序不重要,聚簇索引沒必要
- 插入速度嚴重依賴插入順序(按主鍵順序插入)
- 更新聚簇索引列的代價高
5.3.6 覆蓋索引
如果一個索引包含所有需要查詢的欄位的值(索引列的值),稱它為覆蓋索引 優點:
- 索引條目遠小於資料行大小
- 索引按列值儲存的,對於IO密集型的範圍查詢比隨機IO少得多
- 對InnoDB表很有用,InnoDB的二級索引在葉子節點中保留了行的主鍵值,如果二級主鍵能覆蓋查詢,則可以避免對主鍵索引的二次查詢
MySQL不能在索引中執行LIKE操作
查詢只能使用索引的最左前列,直到遇到第一個範圍查詢為止 隨著偏移量的增加,MySQL花大量時間掃描已放棄的資料,反正規化化,預先計算和快取是唯一的辦法。
另一種是延遲關聯。使用覆蓋索引查詢返回需要的主鍵。再通過主鍵關聯原表獲得需要的行。