作者:張政俊
前言
在測試過程中,發現有一部分在MySQL裡執行很流暢的SQL,放入TiDB中執行耗時明顯變長,有些甚至都跑不出結果。
這裡簡單總結下,上述情況産生的原因、優化辦法、以及遇到無法優化的,如何向社群提供背景資料。
情況與方案
表結構以及資料量MySQL和TiDB都是一緻的,資料庫所在伺服器的硬體配置也差不多。
一. 統計資訊問題
在我們的測試場景中,這類情況很容易出現,因為我們每次跑測試任務前,都是通過br去恢複資料的。
如何判斷
這類問題也比較好判斷,首先就是看執行計劃:
explain analyze SQL;

可以看到
operator info
這列裡出現了
stats:pseudo
,這就代表 paycore_orderinfo 這張表需要重新收集下統計資訊。
優化方案
重新收集該表的統計資訊:
analyze table paycore_orderinfo;
收集完統計資訊後,我們再跑下sql:
可以看到原本是掃描了paycore_orderinfo全表,現在用到create_time索引了,執行時間從7秒減少到0.15秒。
如果想一次找出所有慢查詢裡計資訊為 pseudo的SQL,可以使用以下語句:
select query, query_time, stats from information_schema.slow_query where is_internal = false and stats like '%pseudo%';
二. 優化器問題一
統計資訊的問題比較常見也比較好解決,如果想要解決優化器導緻執行計劃偏差的問題,就需要下一定功夫了。
如何判斷
因為整個SQL比較複雜,就截取當中的一小段,先看下這條SQL在MySQL下的執行計劃:
可以看到整個SQL的執行計劃還是較好的,運作速度也很快。
相同的SQL放到TiDB中執行,執行計劃如下:
在MySQL裡t表用到了primary key,而在TiDB中,t表則使用了idx_ta_ack_2(ta_no)這個索引,導緻實際影響的行數actRows達到了200多萬行,最終整個SQL執行失敗,報錯為:
[Err] 1105 - Out Of Memory Quota![conn_id=226083]
優化方案
現在單獨把這條SQL表關聯的地方拿出來:
FROM
t
LEFT JOIN d ON (t.app_no = d.ack_no),
e
WHERE
為了讓TiDB優化器更好地去判斷,把表關聯順序改為:
FROM
e
STRAIGHT_JOIN t
LEFT JOIN d ON (t.app_no = d.ack_no)
WHERE
執行計劃如下:
t表用回了primary key,跑起來的耗時也比MySQL快了不少。
三. 優化器問題二
還有種情況,在MySQL裡執行計劃正常,但是在TiDB中表關聯被轉為了全表的hashjoin。
如何判斷
先看下MySQL中的執行計劃:
TiDB中的執行計劃:
可以看到g表是
TableFullScan
,這樣整個SQL的執行時間就變得很長。
優化方案
為了讓g表能正常的走到索引關聯,這邊在SQL裡加了hint,加完hint的執行計劃如下:
SQL執行時間也恢複了正常。
因為SQL實在是太長,不便于放在文章展示,是以隻截取了一部分。
這裡想說的是,一般優化器的問題會出現很複雜、join關系很密集的SQL中,處理的方式大緻有三種:
- SQL加hint;
- 通過binding綁定執行計劃;
- 更改表的的連接配接關系;
大家可以通過實際情況進行優化,如果還是解決不了,可以收集相關資訊在社群進行提問。
四. 向社群提問
如果想向社群求助,那需要那些東西呢?
1. 問題SQL
完整的SQL,如果有隐私資訊記得替換掉。
2. 表結構
SQL中所有表的建表語句,以及表中所包含的索引。
3. 執行計劃
通過 explain analyze 執行後輸出的執行計劃。
如果遇到SQL過大,被kill掉,無發跑出執行計劃的情況,那可以通過EXPLAIN FOR CONNECTION指令擷取動态的執行計劃,指令如下:
EXPLAIN FOR CONNECTION ID; #ID為正在執行的SQL ID
4. 表的統計資訊
收集方式:
curl http://172.16.XXX.XXX:10080/stats/dump/schema_name/table_name > dump.txt
收集完以上四樣東西,就可以去社群發帖啦。
總結
- 仔細分析執行計劃,執行計劃裡有足夠多的資訊。
- 遇到pseudo,擇時進行analyze table操作。
- 如果是優化器判斷的問題,根據統計資訊進行sql綁定或更改表連接配接方式(這個需要非常謹慎,不像加hint,更改連接配接方式需要動代碼,關聯邏輯和結果必須得是正确的)。
- 收集所有相關的資訊向社群求助。