Mysql優化之建立高性能索引(一)

1.索引基礎sql

索引對於良好的性能很是關鍵。尤爲是當表中的數據量愈來愈大時,索引對性能的影響愈發重要。可是不恰當的索引隨着數據量的增長,也會使整個數據庫的性能降低。數據庫

舉個例子:性能優化

select a from b where id = 5;

若是在id上創建索引,則Mysql會使用該索引找到id爲5的行,也就是說,Mysql如今索引按值進行查找,而後返回全部包含該值的數據行。索引也能夠包含一列或者多列,列的順序也十分重要,由於Mysql只能高效地使用索引的最左前綴列。性能

索引優化應該是查詢性能優化最有效的手段了,一個「最優」的索引有時比一個「好的」索引性能要好兩個數量級,因此索引的學習不管對開發者或者DBA來講都極爲重要。學習

2.索引類型優化

B-Tree索引url

人們在談論索引時,若無指定,通常爲B-Tree類型的索引,Mysql大部分引擎支持B-Tree索引,但在不一樣的存儲引擎中,B-Tree也可能以不一樣存儲結構實現,好比InnoDB則使用B+Tree。存儲引擎以不一樣的方式使用B-Tree索引,性能優劣各有不一樣。spa

B-Tree一般意味着全部的值都是按順序存儲的,而且每個葉子頁到根的距離相同。下圖爲B-Tree(B+Tree)索引的抽象表示,大體反映了InnoDB索引是如何工做的。MyISAM使用的結構有所不一樣,但基本思想是相似的。指針

這種類型的索引的好處是查詢時不須要進行全盤掃描而是從根節點開始搜索,經過比較找到相應的值並進入下層子節點。因此B-Tree比較適合查找範圍數據,例如像「找出全部I到K開頭的名字」。code

假設有以下數據表:

CREATE TABLE People (
       last_name  varcher(50) not null,
       first_name  varcher(50) not null,
       dob date not null,
       gender enum('m', 'f') not null,
       key(last_name, first_name, dob)
);   

對於表中的每一行數據,索引中包含了last_name,first_name,dob列的值,下圖顯示了該索引是如何組織數據的存儲的。

  • 這裏要注意的是,索引對多個值進行排序的依據是CREATE TABLE語句中定義時列的順序(好比上文的順序爲last_name,first_name,dob)。

下面列舉一些B-Tree索引的經常使用的查詢類型:

  • 全值比配 全值匹配指的是和索引中的全部列進行匹配,例如索引可用於查找姓名爲Cuba Allen、出生於1960-01-01的人
  • 匹配最左前綴 例如查找全部姓Allen的人,即只使用索引的第一列
  • 匹配列前綴 也能夠只匹配某一列的值的開頭部分。例如前面提到的索引可用於查找全部以J開頭的姓的人。這裏也只使用了索引的第一列
  • 匹配範圍值 例如前面提到的索引可用於查找姓在Allen和Barrymore之間的人。這裏也只使用了索引的第一列
  • 精確匹配某一列並範圍匹配另一列 例如像查找全部姓爲Allen,而且名字是字母K開頭的人。即第一列last_name全匹配,第二列first_name範圍匹配
  • 只訪問索引的查詢 即查詢只須要訪問索引,而無須訪問數據行。

除了按值查找外,索引還能夠用於ORDER BY操做。

下列關於B-Tree索引的一些限制:

  • 若是不是按照索引的最左列開始查找,則沒法使用索引。例如上面例子中沒法用於查找名字爲Bill的人,也沒法查找某個特定生日的人,由於這兩列都不是最左數據列。
  • 不能跳過索引中的列,例如查找Smith而且在某個特定生日的人,若是不指定first_name,則Mysql只能用上索引的第一列
  • 若是查詢中有某個列的範圍查詢,則其右邊的列都沒法使用索引優化查找。好比 where last_name='Smith' AND first_name LIKE '%J%' AND dob= '1976-01-01',這個查詢只能用上前兩列索引,但若是範圍查詢數量有限,則能夠優化爲多個等於條件進而使用上索引

哈希索引

哈希索引基於哈希表實現,只有精確匹配索引全部列的查詢纔有效。在Mysql中只有Memory引擎顯式支持哈希索引。

好比: SELECT A FROM B WHERE name='PETER';

Mysql會先計算'PETER'的哈希值,並使用該值尋找對應的指針記錄。由於索引自身只需存儲對應的哈希值,因此哈希索引查找速度很是快,可是也有一些限制:

  • 哈希索引只包含哈希值和行指針,不存儲字段值,因此不能使用索引中的值來避免讀取行
  • 哈希索引不是順序存儲,沒法用於排序
  • 哈希索引也不支持索引列匹配查找,例如KEY(A,B),若是查詢只有數據列A則沒法使用該索引
  • 哈希索引只支持等值比較查詢
  • 當出現哈希衝突時,存儲引擎必須便利鏈表中全部的行指針,直到找到匹配的行
  • 哈希衝突不少的話,一些索引維護操做的代價也會很高

由於這些限制,哈希索引使用的場景有限,而一旦適合哈希索引時,則它帶來的性能提高將很是高。

固然,對於InnoDB來講也能夠建立一個僞哈希列來進行排序查找也是能夠的。

下面有個實例,例如須要存儲大量URL,若是使用B-Tree來存儲URL,存儲的內容會很大,由於URL自己很長,正常狀況下會有以下查詢:

SELECT ID FORM URL WHERE url='http://www.baidu.com'

若刪除原來的URL列上的索引,而新增一個被索引的url_crc列,使用CRC32作哈希,就可使用下面的方式查詢:

 SELECT ID FROM URL WHERE url='http://www.baidu.com' AND url_crc=CRC32("http://www.baidu.com"); 

這樣作的性能會比單獨在url列上開索引高不少,但缺陷就是須要維護哈希值,能夠手動維護,也可使用觸發器實現,例如:

//建立表
CREATE TABLE pseudo hash(
        id int unsigned not null auto_increment,
        url archer(255) not null,
        url_crc int unsigned not null default 0,
        primary key(id)      
);    
//建立觸發器
DELIMITER //
CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN
SET NEW.url_crc=crc32(NEW.url);
END;
//
CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR ROW BEGIN
SET NEW.url_crc=crc32(NEW.url);
END;
//
DELIMITER ;

若是數據表很是大,crc32可能也會出現大量的哈希衝突,這個時候也可使用其餘方案代替,好比md5

處理哈希衝突時,必須在WHERE子句中包含常量值:

SELECT ID FROM URL WHERE url_crc=crc32('http://www.baidu.com') AND url='http://www.baidu.com';

還有一些其餘的索引類型,例如空間數據索引,全文索引,這裏暫時不介紹了,你們能夠自行搜索。

相關文章
相關標籤/搜索