關於SQL優化,這個問題,相信你們過多過少都有過一些瞭解。最近我也在研究SQL優化方面的東西,分享一些經驗。
首先簡單介紹下索引,"索引" 是SQL優化中很重要的一部分(可是索引並非優化的惟一選項)html
如何理解索引?索引其實就是一種數據結構,用於快速定位和訪問數據庫中的數據。mysql
一般來講索引使用的數據結構是 B-Tree / B+Tree。以B-Tree爲例,假設每一個節點存儲100個Key,三層的B-Tree 可存儲一百萬數據,若是將根節點存入內存中的話,只須要讀取兩次磁盤就能夠從100萬數據中找到指定數據web
關於B-Tree 推薦閱讀這篇 https://www.geeksforgeeks.org/introduction-of-b-tree-2/ 包含B-Tree的查詢,新增,刪除操做如何實現算法
SQL優化中查看執行計劃是必不可少的一項,經過 explain
關鍵字能夠查看MySQL中的執行計劃sql
注:G 含義是縱向顯示結果
若是以前沒有了解的 EXPLAIN 的同窗,看到這個列表確定是一臉懵逼。不要緊咱們先來挑幾個重要的屬性認識一下。數據庫
關於explain
再擴展一下,先執行 explain extended ...;
,再執行 SHOW WARNINGS
能夠看到MySQL優化器對咱們的SQL作了什麼優化。以下圖所示服務器
使用索引的優勢:減小服務器掃描的數據量、避免排序和臨時表、將隨機I/O變爲順序I/O
經過下圖,咱們能夠看到,添加了索引以後掃描行數從三十萬行降到了1,性能提高可想而知數據結構
生產環境要注意,建立索引是一個很是耗時的操做,而且會阻塞其餘操做。生產環境添加索引有沒有什麼完美方案?
有的,若是你的MySQL使用主從策略的時候,能夠像Nginx不停機升級web服務那樣,先移除一個節點爲該節點執行ALTER TABLE
操做,而後巴拉巴拉,由於具體我也沒操做過就不細說了,感興趣你們能夠Google一下,動手嘗試一下。若是是單機部署的話,只能用戶少的時候在執行這種操做了函數
索引也能夠提升錶鏈接的性能,下面是個例子,用戶表左連訂單表,對user_id 添加索引的先後對比性能
經過上述例子,咱們能夠看出,若是模糊查詢時以%
開頭的話,MySQL沒法使用索引,可是一般來講模糊查詢時咱們的匹配方式都會是 %xxx%
,那麼如何優化呢?
這裏能夠經過存"反值"的方式巧妙的解決這個問題,例如我如今在數據庫加一列 reverse_order_no 存儲訂單號的反值(並添加索引),匹配的時候再經過 REVERSE('%910') 函數將參數取反。
這裏也可使用 or,以下圖,查看執行計劃會發現Extra 屬性返回 "Using sort_union(order_no,reverse_order_no); Using where"
這裏表明MySQL發生了索引合併,後文咱們會講到
排序須要加索引!相信你們可能知道這個道理,可是以下圖所示,user_id 和 addtime 兩列都創建了索引,那麼下面這條查詢排序使用索引了嗎?
答案是:並無!爲何?注意 Extra 中的 using filesort,表明MySQL 使用了內部文件排序算法對結果集進行了排序。MySQL 一般在一個表上只選擇一個索引(有例外的狀況),這種狀況若是咱們但願排序使用索引的話,能夠創建一個多列索引,以下圖所示
並且多列索引最左邊的列,能夠看成單列索引來使用
咱們剛剛說過 MySQL 一般在一個表上只選擇一個索引,如何理解?例如索引A和索引B 一個須要掃描十萬行,一個須要掃描五萬行,那麼MySQL必定選擇開銷最小的索引方式。
在一些特殊狀況下,MySQL 會選擇 Index Merge(索引合併),即在一個表上使用多個索引
根據MySQL 5.7開發文檔所示,還有一種會使用intersect,InnoDB 主鍵上的任何範圍搜索
關於Index Merge的更多信息,參考MySQL開發文檔
https://dev.mysql.com/doc/refman/5.7/en/index-merge-optimization.html
添加索引雖然能夠提高咱們的SQL性能,可是隨之而來也會帶來必定的開銷
能夠看到在添加了索引以後,空間佔用是原來的7倍,在數據量龐大時,這是一個須要關注的點。
還有須要注意的一點是,在MySQL Innodb 中有聚簇索引和二級索引,通常來講主鍵就是聚簇索引,而其餘的索引都是二級索引。二級索引所存儲的值是聚簇索引。因此當使用二級索引來進行檢索時,MySQL 會先經過該索引找到對應的聚簇索引,再經過該聚簇索引找到對應的數據。這時使用佔用字節更小的類型來作主鍵會更好,會節省索引佔用空間
Effective MySQL之SQL語句最優化