輕鬆優化MySQL-之索引優化2
索引的分類
索引是在儲存引擎中實現的,也就是說不同的儲存引擎,會使用不同的索引。MyISAM和InnoDB儲存引擎:只支援BTREE索引,也就是說預設使用BTREE,不能夠更換,MySQL5.7中InnoDB可以支援HASH索引;MEMORY/HEAP儲存引擎:支援HASH和BTREE索引。索引可劃分為單列索引(其中包括普通索引、唯一索引、主鍵索引)、組合索引、全文索引、空間索引,其中單列索引是一個索引只包含單個列,但一個表中可以有多個單列索引。
普通索引
MySQL中基本索引型別,沒有什麼限制,允許在定義索引的列中插入重複值和空值,純粹為了查詢資料更快一點。
Index(xx)或者 key(xx)
唯一索引
索引列中的值必須是唯一的,但是允許為空值,
UNIQUE INDEX UniqIdx(xx)
主鍵索引
是一種特殊的唯一索引,不允許有空值。
PRIMARY KEY(id)
組合索引
在表中的多個欄位組合上建立的索引,只有在查詢條件中使用了這些欄位的左邊欄位時,索引才會被使用,使用組合索引時遵循最左字首集合。
INDEX MultiIdx(id,name,age)
由id、name和age3個欄位構成的索引,索引行中就按id/name/age的順序存放,索引可以索引下面欄位組合(id,name,age)、(id,name)或者(id)。如果要查詢的欄位不構成索引最左面的字首,那麼就不會是用索引,比如,age或者(name,age)組合就不會使用索引查詢
全文索引
全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT型別欄位上使用全文索引。全文索引就是在一堆文字中,通過其中的某個關鍵字等,就能找到該欄位所屬的記錄行,比如有"你是個大牛,神人 ..." 通過大牛,可能就可以找到該條記錄。這裡說的是可能,因為全文索引的使用涉及了很多細節,我們只需要知道這個大概意思。
FULLTEXT INDEX FullTxtIdx(info) SELECT * FROM t4 WHERE MATCH(info) AGAINST('gorlr');
空間索引
只有在MyISAM引擎上才能使用,空間索引是對空間資料型別的欄位建立的索引,MySQL中的空間資料型別有四種,GEOMETRY、POINT、LINESTRING、POLYGON。
在建立空間索引時,使用SPATIAL關鍵字。
建立空間索引的列,必須將其宣告為NOT NULL。。
SPATIAL INDEX spatIdx(g)
索引優化口訣
全值匹配我最愛,最左字首要遵守;
帶頭大哥不能死,中間兄弟不能斷;
索引列上少計算,範圍之後全失效;
Like百分寫最右,覆蓋索引不寫星;
不等空值還有or,索引失效要少用;
VAR引號不可丟,SQL高階也不難!
參考: <u>https://blog.csdn.net/zjy15203167987/article/details/81812370</u>
參考: <u>https://www.jianshu.com/p/d5b2f645d657</u>
覆蓋索引
如果索引包含滿足查詢的所有資料,就稱為覆蓋索引。覆蓋索引是一種非常強大的工具,能大大提高查詢效能。只需要讀取索引而不用讀取資料有以下一些優點:
(1) 索引項通常比記錄要小,所以MySQL訪問更少的資料;
(2) 索引都按值的大小順序儲存,相對於隨機訪問記錄,需要更少的I/O;
(3) 大多資料引擎能更好的快取索引。比如MyISAM只快取索引。
(4) 覆蓋索引對於InnoDB表尤其有用,因為InnoDB使用聚集索引組織資料,如果二級索引中包含查詢所需的資料,就不再需要在聚集索引中查找了。
覆蓋索引不能是任何索引,只有B-TREE索引儲存相應的值。而且不同的儲存引擎實現覆蓋索引的方式都不同,並不是所有儲存引擎都支援覆蓋索引(Memory和Falcon就不支援)。
對於索引覆蓋查詢(index-covered query),使用EXPLAIN時,可以在Extra一列中看到“Using index”。
案例實踐
場景
產品中有一張圖片表,資料量將近100萬條,有一條相關的查詢語句,由於執行頻次較高,想針對此語句進行優化。表結構很簡單,主要欄位:
user_id 使用者ID
picname 圖片名稱
smallimg 小圖名稱
一個使用者會有多條圖片記錄,現在有一個根據user_id建立的索引:uid,查詢語句也很簡單。取得某使用者的圖片集合
select picname, smallimg from pics where user_id = xxx;
優化前
執行查詢語句(為了檢視真實執行時間,強制不使用快取)
select SQL_NO_CACHE picname, smallimg from pics where user_id=17853;
執行了10次,平均耗時在40ms左右。使用explain進行分析
explain select SQL_NO_CACHE picname, smallimg from pics where user_id=17853

image.png
使用了user_id的索引,並且是const常數查詢,表示效能已經很好了
優化後
因為這個語句太簡單,sql本身沒有什麼優化空間,就考慮了索引。修改索引結構,建立一個(user_id,picname,smallimg)的聯合索引:uid_pic。重新執行10次,平均耗時降到了30ms左右。使用explain進行分析

image.png
看到使用的索引變成了剛剛建立的聯合索引,並且Extra部分顯示使用了'Using Index'
總結
'Using Index'的意思是“覆蓋索引”,它是使上面sql效能提升的關鍵。一個包含查詢所需欄位的索引稱為“覆蓋索引”,MySQL只需要通過索引就可以返回查詢所需要的資料,而不必在查到索引之後進行回表操作,減少IO,提高了效率。
例如上面的sql,查詢條件是user_id,可以使用聯合索引,要查詢的欄位是picname smallimg,這兩個欄位也在聯合索引中,這就實現了“覆蓋索引”,可以根據這個聯合索引一次性完成查詢工作,所以提升了效能
InnoDB行鎖優化建議
InnoDB儲存引擎由於實現了行級鎖定,雖然在鎖定機制的實現方面帶來的效能損耗可能比表級鎖定要更高一些,但是在整體併發處理能力方面是要遠遠優於MyISAM的表級鎖定的。當系統併發量較高的時候,InnoDB的整體效能和MyISAM相比就會有比較明顯的優勢了。但是當我們使用不當的時候,可能會讓InnoDB的整體效能表現不僅不比MyISAM高,甚至可能會更差。
建議:
(1)儘可能讓所有的資料檢索都通過索引來完成,從而避免InnoDB因為無法通過索引鍵加鎖而升級為表級鎖定
(2)合理設計索引,讓InnoDB在索引鍵上面加鎖的時候儘可能準確,儘可能地縮小鎖定範圍,避免造成不必要的鎖定而影響其他Query的執行
(3)儘可能減少基於範圍的資料檢索過濾條件,避免因為間隙鎖帶來的負面影響而鎖定了不該鎖定的記錄
(4)儘量控制事務的大小,減少鎖定的資源量和鎖定時間長度
(5)在業務環境允許的情況下,儘量使用較低級別的事務隔離,以減少MySQL因為實現事務隔離級別所帶來的附加成本。