MySQL憑借著出色的性能、低廉的成本、豐富的資源,已經成為絕大多數互聯網公司的首選關系型數據庫。雖然性能出色,但所謂“好馬配好鞍”,如何能夠更好的使用它,已經成為開發工程師的必修課,我們經常會從職位描述上看到諸如“精通MySQL”、“SQL語句優化”、“了解數據庫原理”等要求。我們知道一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現性能問題,遇到最多的,也是最容易出問題的,還是一些復雜的查詢操作,所以查詢語句的優化顯然是重中之重。
本人從13年7月份起,一直在美團核心業務系統部做慢查詢的優化工作,共計十余個系統,累計解決和積累了上百個慢查詢案例。隨著業務的復雜性提升,遇到的問題千奇百怪,五花八門,匪夷所思。本文旨在以開發工程師的角度來解釋數據庫索引的原理和如何優化慢查詢。
一個慢查詢引發的思考
| select count(*) from task where status=2 and operator_id=20839 and operate_time>1371169729 and operate_time<1371174603 and type=2; |
系統使用者反應有一個功能越來越慢,于是工程師找到了上面的SQL。
并且興致沖沖的找到了我,“這個SQL需要優化,給我把每個字段都加上索引”
我很驚訝,問道“為什么需要每個字段都加上索引?”
“把查詢的字段都加上索引會更快”工程師信心滿滿
“這種情況完全可以建一個聯合索引,因為是最左前綴匹配,所以operate_time需要放到最后,而且還需要把其他相關的查詢都拿來,需要做一個綜合評估。”
“聯合索引?最左前綴匹配?綜合評估?”工程師不禁陷入了沉思。
多數情況下,我們知道索引能夠提高查詢效率,但應該如何建立索引?索引的順序如何?許多人卻只知道大概。其實理解這些概念并不難,而且索引的原理遠沒有想象的那么復雜。
MySQL索引原理
索引目的
索引的目的在于提高查詢效率,可以類比字典,如果要查“mysql”這個單詞,我們肯定需要定位到m字母,然后從下往下找到y字母,再找到剩下的sql。如果沒有索引,那么你可能需要把所有單詞看一遍才能找到你想要的,如果我想找到m開頭的單詞呢?或者ze開頭的單詞呢?是不是覺得如果沒有索引,這個事情根本無法完成?
索引原理
除了詞典,生活中隨處可見索引的例子,如火車站的車次表、圖書的目錄等。它們的原理都是一樣的,通過不斷的縮小想要獲得數據的范圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是我們總是通過同一種查找方式來鎖定數據。
數據庫也是一樣,但顯然要復雜許多,因為不僅面臨著等值查詢,還有范圍查詢(>、<、between、in)、模糊查詢(like)、并集查詢(or)等等。數據庫應該選擇怎么樣的方式來應對所有的問題呢?我們回想字典的例子,能不能把數據分成段,然后分段查詢呢?最簡單的如果1000條數據,1到100分成第一段,101到200分成第二段,201到300分成第三段......這樣查第250條數據,只要找第三段就可以了,一下子去除了90%的無效數據。但如果是1千萬的記錄呢,分成幾段比較好?稍有算法基礎的同學會想到搜索樹,其平均復雜度是lgN,具有不錯的查詢性能。但這里我們忽略了一個關鍵的問題,復雜度模型是基于每次相同的操作成本來考慮的,數據庫實現比較復雜,數據保存在磁盤上,而為了提高性能,每次又可以把部分數據讀入內存來計算,因為我們知道訪問磁盤的成本大概是訪問內存的十萬倍左右,所以簡單的搜索樹難以滿足復雜的應用場景。
新聞熱點
疑難解答