本文為Percona的Practical MySQL Performance Optimization第3節(jié)的筆記,基礎(chǔ)知識(shí)為主幌羞。
索引
InnoDB和MyISAM都支持B-tree索引窘问,可以支持快速的相等查詢(xún)(例如id = 1)和范圍查詢(xún)(例如>、<和in)。InnoDB的主鍵索引還是聚簇的抓督,數(shù)據(jù)和主鍵放一起,獲取數(shù)據(jù)會(huì)更快束亏。
索引使用
explain
可以查看MySQL對(duì)一個(gè)語(yǔ)句的執(zhí)行計(jì)劃铃在,其中的key
是查詢(xún)使用的索引。
MySQL查詢(xún)的時(shí)候只會(huì)對(duì)每個(gè)表用一個(gè)索引碍遍,而且只用這個(gè)索引的最左前綴定铜。
例如對(duì)一個(gè)三個(gè)字段組成的組合索引Comb(CountryCode, District, Population)
MySQL可以用下面這3個(gè)部分:
- 只用
CountryCode
部分 - 只用
CountryCode + District
部分 - 用
CountryCode + District + Population
全部
組合索引中各部分的順序也會(huì)影響查詢(xún),最好是先比較相等的字段怕敬,再到范圍字段揣炕。
查詢(xún)計(jì)劃中可以根據(jù)key_len
或JSON格式的查詢(xún)計(jì)劃中used_key_parts
來(lái)判斷用了索引的那個(gè)部分畸陡。
覆蓋索引就是覆蓋了一個(gè)查詢(xún)中Select、Where虽填、Group by罩锐、Order by出現(xiàn)的全部字段的索引。
查詢(xún)
Group by優(yōu)化
沒(méi)有索引的情況下要掃描整個(gè)表卤唉,還會(huì)用臨時(shí)表存放結(jié)果涩惑。
篩選條件是相等比較時(shí),用包含篩選條件和Group by字段的組合索引(或覆蓋索引)桑驱,可以避免臨時(shí)表竭恬。(效果類(lèi)似上面的圖,先通過(guò)篩選條件的索引找到Group的索引熬的,根據(jù)Group的索引知道Group的個(gè)數(shù)和數(shù)據(jù)的位置痊硕,然后對(duì)每個(gè)Group掃描就可以了)。
如果篩選條件是范圍查詢(xún)押框,可以已通過(guò)union改成多個(gè)查詢(xún)合并岔绸,來(lái)減少臨時(shí)表的大小(每個(gè)查詢(xún)不用臨時(shí)表橡伞,但最后合并要)盒揉。
在對(duì)一個(gè)表進(jìn)行Group by,Group by條件只包含索引的最左前綴兑徘,而且只用max/min對(duì)這個(gè)索引的前綴進(jìn)行聚合運(yùn)算刚盈,MySQL可以進(jìn)行松散的索引掃描,只用掃描少部分的索引挂脑,很快藕漱。(應(yīng)該是索引里直接保存了max/min的結(jié)果來(lái)減少對(duì)一課子樹(shù)的掃描)欲侮。
Order by優(yōu)化
Order by查詢(xún)數(shù)據(jù)多的時(shí)候要進(jìn)行文件排序,而索引是已經(jīng)排序的肋联,可以避免文件排序威蕉,Limit條數(shù)較少也可以避免文件排序。
計(jì)算表達(dá)式
如果查詢(xún)條件里有函數(shù)橄仍,MySQL是不能用函數(shù)參數(shù)上的索引快速篩選的忘伞,這時(shí)通常要用單獨(dú)的一列保存函數(shù)調(diào)用的結(jié)果,但是要在應(yīng)用層或觸發(fā)器保證正確更新沙兰。MySQL 5.7有了虛擬/生成字段氓奈,可以直接在一個(gè)虛擬字段里保存函數(shù)調(diào)用的結(jié)果,虛擬字段不會(huì)被保存鼎天,但是可以建索引舀奶!