天天看點

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

問題

我們有一個 SQL,用于找到沒有主鍵 / 唯一鍵的表,但是在 MySQL 5.7 上運作特别慢,怎麼辦?

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

實驗

我們搭建一個 MySQL 5.7 的環境,此處省略搭建步驟。

寫個簡單的腳本,制造一批帶主鍵和不帶主鍵的表:

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

執行一下腳本:

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

現在執行以下 SQL 看看效果:

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

...

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

執行了 16.80s,感覺是非常慢了。

現在用一下 DBA 三闆斧,看看執行計劃:

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

感覺有點慘,由于 information_schema.columns 是中繼資料表,沒有必要的統計資訊。

那我們來 show warnings 看看 MySQL 改寫後的 SQL:

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

我們格式化一下 SQL:

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

可以看到 MySQL 将

select from A where A.x not in (select x from B) //非關聯子查詢
           

轉換成了

select from A where not exists (select 1 from B where B.x = a.x) //關聯子查詢
           

如果我們自己是 MySQL,在執行非關聯子查詢時,可以使用很簡單的政策:

select from A where not exists (select 1 from B where B.x = a.x and ...) //關聯子查詢掃描 A 表的每一條記錄 rA:     掃描 B 表,找到其中的第一條滿足 rA 條件的記錄。
           

而關聯子查詢就需要循環疊代:

select from A where not exists (select 1 from B where B.x = a.x and ...) //關聯子查詢掃描 A 表的每一條記錄 rA:     掃描 B 表,找到其中的第一條滿足 rA 條件的記錄。
           

顯然,關聯子查詢的掃描成本會高于非關聯子查詢。

我們希望 MySQL 能先"緩存"子查詢的結果(緩存這一步叫物化,MATERIALIZATION),但MySQL 認為不緩存更快,我們就需要給予 MySQL 一定指導。

mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生
mysql group by 查詢慢_MySQL 表上做查詢慢出現狀況-愛可生

可以看到執行時間變成了 0.67s。

整理

我們診斷的關鍵點如下:

1. 對于 information_schema 中的中繼資料表,執行計劃不能提供有效資訊。

2. 通過檢視 MySQL 改寫後的 SQL,我們猜測了優化器發生了誤判。

3. 我們增加了 hint,指導 MySQL 正确進行優化判斷。

但目前我們的實驗僅限于猜測,猜中了萬事大吉,猜不中就無法做出好的診斷。