故障分析 MySQL 優化案例 字符集轉換

2021-10-07 15:21:19 字數 4217 閱讀 4694

server version: 5.7.24-log mysql community server (gpl)

開發聯絡我,說是開發庫上有一張檢視查詢速度很慢,9000 條資料要查 10s,要求我這邊協助排查優化。

這個 sql 非常簡單,定義如下,其中就引用了view_dataquality_analysis這張檢視,後面跟了兩個 where 條件,並且做了分頁。

select *

from view_dataquality_analysis

where modelguid = '710adae5-1900-4207-9864-d53ee3a81923'

and configurationguid = '6845d000-cda4-43ea-9fd3-9f9f1f22f95d' limit 20;

我們先去開發庫上執行一下這條 sql,下圖中可以看到確實執行很慢,要 8s 左右。

分析一條慢 sql,最有效的方法便是分析它的執行計畫,看是否存在問題。

下面我們看下這條 sql 的執行計畫,主要由三張表(t、r、b)組成,從t開始巢狀連線r,再巢狀連線b。整個執行邏輯很簡單,至於 t、r、b 肯定是檢視中定義的表別名。

從執行計畫中可以看出t巢狀連線r的時候走的是主鍵索引,但是繼續巢狀連線b的時候,卻是走的全表掃瞄! 那麼可能很有可能問題就出在這個地方,為什麼b表沒有走索引,是因為缺失了索引嗎?

帶著上面執行計畫中的疑問,我們去看下view_dataquality_analysis這張檢視的定義,如下所示。

select *

from (

( `dataquality_taskconfigurationhistory` `t` left join `dataquality_rule` `r` on ((`t`.`ruleguid` = `r`.`ruleguid`))

) left join `metadata_tablebasicinfo` `b` on ((convert(`b`.`tableguid` using utf8mb4) = `r`.`tableguid`))

)

檢視由dataquality_taskconfigurationhistorydataquality_rulemetadata_tablebasicinfo表連線組成,分別用了t、r、b 別名表示。因為都是用的left join,所以表連線順序應該是 t–>r–>b,和之前執行計畫中顯示的一致。

不知道各位有沒有注意到

(convert(`b`.`tableguid` using utf8mb4) = `r`.`tableguid`))
這一段內容!表連線上居然存在乙個字符集的轉換。那麼問題可能就是出在這裡。

起先我以為這一段字符集轉換是開發在定義檢視的時候自己加上去的,後來詢問後發現開發並未如此做。嘗試將檢視定義去掉這一段內容,但是發現儲存後,這個轉換卻會自動生成!!!

帶著上面的疑問,我們去看下表定義,首先是bmetadata_tablebasicinfo,然後是rdataquality_rule,最後是tdataquality_taskconfigurationhistory

create table `metadata_tablebasicinfo` (

`tableguid` varchar(50) not null,

`sqltablename` varchar(50) default null,

.......

primary key (`tableguid`)

) engine=innodb default charset=utf8

create table `dataquality_rule` (

`ruleguid` varchar(50) not null,

`modelguid` varchar(50) default null,

.......

primary key (`ruleguid`),

key `idx_top` (`ruleguid`,`tableguid`)

) engine=innodb default charset=utf8mb4

create table `dataquality_taskconfigurationhistory` (

`rowguid` varchar(50) not null,

`modelguid` varchar(50) default null,

.......

primary key (`rowguid`)

) engine=innodb default charset=utf8mb4

通過檢視表定義後,可以看到b表字符集為 utf8,而t表與r表字符集都為 utf8mb4!!!那麼基本可以驗證我的猜想,當 mysql 建立檢視時,如果發現表連線字段字符集不相同時,會自動新增字符集轉換。

另外之前我們有個為什麼b表沒有走索引,是因為缺失了索引嗎?的疑問。從上面b表的表結構定義就可以看出,b表的連線欄位為tableguid,是b表的主鍵,那麼肯定存在主鍵索引,就更不可能不走索引而選擇全表掃瞄了。

為了驗證因為字符集問題而導致表連線沒有走索引,我們選擇將bmetadata_tablebasicinfo的字符集修改為 utf8mb4。

過程如下:

--修改表的預設字符集和所有列的字符集為utf8mb4

alter table metadata_tablebasicinfo convert to character set utf8mb4;

通過上述操作後,目前b表為 utf8mb4 字符集。

b表字符集修改為 utf8mb4 後,去檢視view_dataquality_analysis檢視定義,發現還是存在字符集轉換,所以猜測這類自動新增轉換的機制因為不會因為表結構更改而自動去掉。

我們再次將檢視中字符集轉換的內容去掉後,儲存檢視,發現這次不會自動新增字符集轉換。那麼這次應該就應該會走索引啦~

我們再次執行問題 sql,執行時間為 0.2s,速度明顯就正常了。

再來看一波執行計畫,可以看到b表上走的是主鍵索引,這下舒服了~

通過這次問題排查,發現了字符集不同原來也會導致索引失效。其實這個問題有點類似於int = varchar隱式轉換問題,等號左邊為 int 型別,右邊為 varchar 型別,那麼 mysql 會自動轉換型別為一致,因而無法走索引。

下次如果再出現類似的問題,可以先檢視下檢視定義,如果存在字符集轉換的內容,那麼就可以檢查是否是類似的問題!

另外還有乙個注意的點就是,列的字符集也有可能與表的字符集不同!

mysql 故障案例 mysql故障案例

錯誤 error 1044 42000 access denied for user root to database dede mysql create database dede error 2006 hy000 mysql server has gone away no connection....

mysql故障案例 mysql故障案例

mysql create database dede error 2006 hy000 mysql server has gone away no connection.trying to reconnect.connection id 47299 current database none que...

mysql優化案例分析

本文總結了一些工作常見的sql優化例子,雖然比較簡單,但很實用,希望對大家有所幫助。sql優化一般分為兩類,一類是sql本身的優化,如何走到合適的索引,如何減少排序,減少邏輯讀 另一類是sql本身沒有優化餘地,需要結合業務場景進行優化。即在滿足業務需求的情況下對sql進行改造,已提高sql執行速度,...