TiDB與MySQL的SQL差異及執行計劃簡析

作者:京東零售 肖勇

一、 前言導讀

TiDB作爲NewSQL,其在對MySQL(SQL92協議)的兼容上做了很多,MySQL作爲當下使用較廣的事務型數據庫,在IT界尤其是互聯網間使用廣泛,那麼對於開發人員來說,1)兩個數據庫產品在SQL開發及調優的過程中,都有哪些差異?在系統遷移前需要提前做哪些準備? 2)TiDB的執行計劃如何查看,如何SQL調優? 本文做了一個簡要歸納,歡迎查閱交流。

二、 建表SQL語法差異&優化建議

三、 查詢SQL語法差異&優化建議

四、 SQL執行計劃差異&優化建議

五、 TiDB執行計劃分析簡介

1. 在開始實際案例分析前,我們先看下執行計劃中每列的含義:

引自:https://docs.pingcap.com/zh/tidb/stable/sql-statement-explain和https://docs.pingcap.com/zh/tidb/stable/sql-statement-explain-analyze

2. 執行計劃優化的幾個關鍵點:

1) 重點觀察算子類型,儘量控制優化器選擇性能較優的算子,讀取磁盤記錄的幾個算子性能:TableFullScan>TableRangeScan>TableRowIDScan,IndexFullScan>IndexRangeScan

2) 儘量減小root層執行動作,下放至tikv或tiflash執行,執行計劃中task屬性包括root task和cop task,其中root標識動作由tidb聚合層執行(此操作除了需要等待各分片結果外,一般部署結構中tidb資源也較tikv或tiflash少),cop標識動作下放至tikv或tiflash各分片單獨執行

3) 保證表分析數據完整性,避免大批量數據短時間內新增/刪除,estRows爲執行引擎根據情況返回的預估記錄條數,特別注意:若operator info出現stats:pseudo,則標識表基本信息不完善(無法提供準確執行計劃評估),後續可通過analyze表重新收集分析數據,或顯示use index對sql顯示優化

4) 根據實際業務(如:列模式數據統計),增加tiflash模塊,通過空間換時間,提升結構化查詢和實時分析能力

3. 實際場景分析

下面我們通過2個實際SQL說說TiDB的執行計劃:

l SQL1

1:IndexLookUp算子:根據索引獲取結果記錄

2 & 3:Build算子總是優先於Probe算子執行,*2 算子根據條件從索引中獲取數據,*3算子在結果中匹配結果

4:TableRowIdScan:通過 *3 算子結果中的表主鍵id從TiKV獲取行記錄

5:cop【tikv】標識將計算邏輯從tidb下放到tikv執行,同理還會有cop【tiflash】

6:tikv通過範圍索引掃描出對應記錄

7:根據id獲取行記錄後直接返回上層,無需排序

------------------------------------------------------------------------------------------------------------------------------

l SQL2

優化前,兩表直接join

explain analyze SELECT m.id AS id, m.order_id AS orderId, s.status AS status,m.sendpay_map as sendPayMap FROM tableA m LEFT JOIN tableB s on m.order_id = s.order_id WHERE m.id >= 100 AND m.id <= 100000000 and m.warehouse_id in (111,222) and s.status in (100, 200, 300, 400) and m.is_valid = 1 order by m.id desc limit 20,20;

1:IndexJoin算子:根據表s索引,與表m關聯起來

2 & 3:Build算子總是優先於Probe算子執行,*2 算子從表m匹配相關記錄,*3算子通過表s索引獲取join管理數據

4 & 5:基於*3算子join後的結果,篩選匹配s表條件的記錄

6 & 7:可以看到此處表記錄查詢使用了TableReader,耗時6.41s(其中cop_task共424個,且使用了大量索引proc_keys),Selection_98根據索引回表查詢更是讀取了3.03GB記錄

總結:整體sql因爲是先join在limit,tidb無法將limit操作下推,導致主表大量回表查詢,影響性能

優化後,先子查詢再join:

explain analyze select * from (SELECT m.id AS id, m.order_id AS orderId,m.sendpay_map as sendPayMap FROM tableA m WHERE m.id >= 100 AND m.id <= 100000000 and m.warehouse_id in (111 ,222) and m.is_valid = 1 order by m.id desc limit 20,20) t LEFT JOIN tableB s on t.orderId = s.order_id WHERE s.status in (100 ,200, 300, 400)

1:IndexJoin算子:根據表s索引,與表m關聯起來

2:從m表結果中獲取前20條記錄

3:通過表s索引獲取join管理數據

4:根據條件,從表m的索引中獲取記錄

5:從*4算子結果中獲取40條記錄(tikv3副本,從2個分片各獲取20條,共40條)

6 & 7:基於*3算子join後的結果,篩選匹配s表條件的記錄

9:可以看到,此處是直接從IndexLookUp_57索引中查詢數據,cop_task=1,且rocksdb中命中了緩存cache_hit_count=11

總結:整體sql因爲是先limit再join,tidb將limit下推至tikv,大大較少了主表的回表查詢數據量,提升性能

六、 小結

本文旨在通過TiDB和MySQl在SQL層面的差異性講解,幫助讀者在DB遷移和評估前,清楚瞭解雙方的差異,避免遺漏。同時,針對TiDB的執行計劃,通過簡介和2個案例,幫助大家快速分析SQL執行情況,以便針對性優化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章