
以下是來自dba+社群mysql領域原創專家李海翔分享的mysql優化案例,關于mysql v5.6.x/5.7.x sql查詢性能問題。
專家簡介
李海翔
網名:那海藍藍
dba+社群mysql領域原創專家
從事資料庫研發、資料庫測試與技術管理等工作10餘年,對資料庫的核心有深入研究,擅長于postgresql和mysql等開源資料庫的核心與架構。現任職于oracle公司mysql全球開發團隊,從事查詢優化技術的研究和mysql查詢優化器的開發工作。著有《資料庫查詢優化器的藝術》一書。
一、簡單建立一表,并使用存儲過程插入一部分資料
二、執行如下查詢
q1:
q2:q2比q1隻多了一個使用or子句連接配接的條件,資料中沒有滿足此條件的資料
問題: q1和q2哪個查詢快?快者比慢者能快出幾倍?為什麼?
三、實際運作結果
對q1和q2稍加改造,目的是避免有大量的查詢結果輸出。目标列使用count()函數替換。
看紅色字型,所耗費的時間,q1是q2的近乎40倍。為什麼?
四、探索原因
第一招:察看執行計劃
對比執行計劃,發現q1使用了“materialized”物化方式存儲子查詢的臨時結果,是不是物化導緻了q1慢呢?
第二招:察看io
q2和q1不一緻之處在于q2的“handler_read_key”值20002遠遠比比q1的2高,這說明q2更多地利用了索引。
且看mysql官方解釋如下:
handler_read_key
the number of requests to read a row based on a key. if this value is high, it is a good indication that your tables are properly indexed for your queries.
問題:
為什麼q2會有更多的索引讀?索引是從哪裡來的?
q1被物化,意味着q1使用了臨時表;而q2子查詢是否被物化是否使用了臨時表呢?
五、新的疑問,再次探索
之下如下操作,注意show warnings技巧的使用。查詢結果作了形式的調整,便于閱讀。
可以看出,q1的子查詢被物化後,又作了半連接配接優化,意味着子查詢被上拉方式優化。
q2表明,首先使用了臨時表,但是和q1不同的是,子查詢沒有被上拉優化。
但是,mysql對于臨時表的使用,會自動建立索引,是以我們能看到在“auto_key”上執行了“primary_index_lookup”。這就是q2快于q1的原因。也是為什麼q2的索引讀計數器的值較大的原因。
問題:半連接配接優化
六、繼續探索
執行計劃似乎改變不大,但類似了q2的執行計劃。(哈哈,可執行show warnings;指令看看,擷取更詳細的資訊才能得出更靠譜的結論)
在禁止了半連接配接操作之後,執行速度一下子坐上了飛機,有了40餘倍的提升。
七、結論
1. q1使用了物化+半連接配接優化,q2是子查詢,但沒有使用半連接配接優化,可見mysql中半連接配接優化的效率未必高。
2. 似乎物化的子查詢用半連接配接上拉,mysql的判斷條件還是存在一點兒問題。
<b></b>
<b>本文來自雲栖社群合作夥伴"dbaplus",原文釋出時間:2015-12-07</b>