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

来源:https://www.cnblogs.com/jingdongkeji/archive/2023/04/17/17324787.html
-Advertisement-
Play Games

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


作者:京東零售 肖勇

一、 前言導讀

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

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

| 分類 | MySQL寫法 | TiDB寫法 | 註意事項 |
| 建表 | alter table A add column phone bigint(20),add column address varchar(100); | alter table A add column phone bigint(20); alter table A add column address varchar(100); | 1.一個DDL腳本僅支持一個欄位修改 2.新建表時,儘量提前規劃好相應欄位 |
| 建表 | create table A(`id` bigint(20) NOT NULL AUTO_INCREMEN) | create table A(`id` bigint(20) NOT NULL AUTO_INCREMEN) | TiDB自增主鍵全局唯一,但不嚴格遞增(僅各Server內部連續) 需要嚴格連續自增主鍵時,業務系統自己生成寫入 |
| 建表 | create table A as select * from B | 不支持 | |
| 建表 | create temporary table A | 不支持 | 不支持臨時表 |
| SQL DML提交前,建議結合explain和explain analyze命令和業務場景,確認執行計劃 |

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

| 分類 | MySQL寫法 | TiDB寫法 | 註意事項 |
| 查詢 (結果條數統計) | select * from A select count() from A | select name,age,address from A select count(age) from A | 1.避免全量欄位查詢,節省網路帶寬 2.當開啟TiFlash統計行數據時,TiDB會使用列模式提升查詢性能 |
| 查詢 (閉區間查詢) | select name,age from A where age>10 | select name,age from A where age>10 and id<99 | TiDB針對限定數據範圍的閉區間查詢,能減少全表掃描概率 |
| 查詢 (時間排序) | select name,age from A order by id(主鍵) | select name,age from A order by create_time(時間索引) | 分散式資料庫主鍵不再連續,需要時間順序排序時,可新增時間欄位 |
| 查詢 (結果欄位分堆) | select name,age from A group by name | select name,age from A group by name,age | 需要分堆的所有欄位,在SQL中必須顯示標識 |
| 查詢 (結果欄位排序) | select name,age from A order by name | select name,age from A order by name,age | 需要排序的所有欄位,在SQL中必須顯示標識 |
| 查詢 (索引優化) | select name,age from A where name=‘張三’ and age>110 and cityName!='北京' | 儘可能的將使用頻率高的,經常被點查使用的列排在前面,將經常進行範圍查詢的列排在後面 |
| 查詢 (顯示優化規則) DBA不建議 | select name,age from A where name='張三' | select name,age from A where name='張三' use index(name_age) | 顯示通知TiDB優化器,使用name_age索引 |
| 查詢 (覆蓋索引) | select name,age from A where name='張三' order by age | ORDER BY,GROUP BY,DISTINCT 的欄位需要添加在索引的後面,形成覆蓋索引 |
| 查詢 (顯示優化規則) DBA不建議 | select name,age from A where name='張三' | select /
+ read_from_storage(tiflash[A]) */ name,age from A where name='張三' | 顯示通知TiDB優化器,使用TiFlash提升性能 |
| MySQL常見SQL優化規則(如not in,like ‘abc%’,減少查詢返回列,避免在索引列使用函數),對於TiDB同樣適用 |

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

| 分類 | MySQL寫法 | TiDB寫法 | 註意事項 |
| 執行計劃 | explain select count() from A | explain select count() from A explain analyze select count(*) from A | 1.TiDB提供explain和explain analyze兩種查詢計劃分析,前者不會執行,後者會實際執行 2.explain參考:https://docs.pingcap.com/zh/tidb/stable/explain-walkthrough 3.explain analyze參考:https://docs.pingcap.com/zh/tidb/stable/sql-statement-explain-analyze/ |
| 查詢 (結果分析優化) | operator中包含stats:pseudo | SQL對應表統計信息已失真,執行analyze tableName修複即可(註:關註數據期間卡表修複對業務的影響) |
| 查詢 (類型優化) | select name,age from A where zip=0 (其中zip為bit類型) | select name,age from A where zip=0 (修改zip為int類型) | TiDB欄位儘量使用常見mysql類型 |
| 註意:analyze tableName對TiDB集群的影響較大,執行前千萬與DBA做好溝通評估,臨時情況可通過顯示指定索引(USE INDEX)繞開流量高峰期 |

五、 TiDB執行計劃分析簡介

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

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

| 屬性名 | 含義 |
| id | 運算元的 ID,是運算元在整個執行計劃中唯一的標識。在 TiDB 2.1 中,ID 會格式化地顯示運算元的樹狀結構。數據從孩子結點流向父親結點,每個運算元的父親結點有且僅有一個。 |
| estRows | 運算元預計將會輸出的數據條數,基於統計信息以及運算元的執行邏輯估算而來。 |
| actRows | 運算元實際輸出的數據條數 |
| task | 運算元屬於的 task 種類。目前的執行計劃分成為兩種 task,一種叫 root task,在 tidb-server 上執行,一種叫 cop task,在 TiKV 或者 TiFlash 上並行執行。當前的執行計劃在 task 級別的拓撲關係是一個 root task 後面可以跟許多 cop task,root task 使用 cop task 的輸出結果作為輸入。cop task 中執行的也即是 TiDB 下推到 TiKV 或者 TiFlash 上的任務,每個 cop task 分散在 TiKV 或者 TiFlash 集群中,由多個進程共同執行。 |
| access object | 運算元所訪問的數據項信息。包括表 table,表分區 partition 以及使用的索引 index(如果有)。只有直接訪問數據的運算元才擁有這些信息。 |
| execution info | 運算元的實際執行信息。time 表示從進入運算元到離開運算元的全部 wall time,包括所有子運算元操作的全部執行時間。如果該運算元被父運算元多次調用 (loops),這個時間就是累積的時間。loops 是當前運算元被父運算元調用的次數。 |
| operator info | 運算元的其它信息。各個運算元的 operator info 各有不同,可參考下麵的示例解讀。 |
| memory | 運算元占用記憶體空間的大小 |
| disk | 運算元占用磁碟空間的大小 |

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執行情況,以便針對性優化。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Redis的Java客戶端 在Redis官網中提供了各種語言的客戶端,地址:Get started using Redis clients | Redis Redis的Java客戶端: 1.Jedis Jedis 的官方地址:redis/jedis: Redis Java client design ...
  • 一、數據類型之列表 列表簡介 Redis的list是一個字元隊列,先進後出,一個key可以有多個值 列表操作 lpush key values [value ...] 將一個或多個值value插入到列表key的表頭,Key不存在,則創建key 127.0.0.1:6379> FLUSHALL OK ...
  • 一、連接MongoDB 工具:==studio 3T== 下載:https://studio3t.com/download-thank-you/?OS=win64 1、無設置密碼 最終成功頁面 2、設置了密碼 後續同1 二、安裝 MongoDB版本:5.0.5 參考: https://www.cnb ...
  • 一、部署LNMP及redis 1、部署LNMP,需要將 tengine-2.2.0.tar.gz 拷貝到虛擬機的 /root 目錄下 步驟一:安裝nginx 源碼安裝相關軟體包 # pcre-devel做正則匹配,zlib-devel做數據壓縮 [root@template ~]# yum -y i ...
  • 如今,數字經濟正逐步走向深化應用、規範發展、普惠共用的新階段,數字經濟與實體經濟深度融合、基礎軟體國產化替代成為數字時代主潮流。數字工具如何讓千行百業共同實現韌性生長? 「 2023 袋鼠雲春季生長大會」乘風而起,帶來數實融合趨勢下的產品煥新升級剖析、前瞻行業視覺解讀、最佳數字實踐分享,助力各大產業 ...
  • 摘要:今天發現Mysql的主從資料庫沒有同步,瞬間整個人頭皮發麻。 本文分享自華為雲社區《糟了,生產環境數據竟然不一致,人麻了!》,作者:冰 河 。 今天發現Mysql的主從資料庫沒有同步 先上Master庫: mysql>show processlist; 查看下進程是否Sleep太多。發現很正常 ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者: 奧特曼愛小怪獸 文章來源:GreatSQL社區投稿 上一篇 MySQL8.0 優化器介紹(一)介紹了成本優化模型的三要素:表關聯順序,與每張表返 ...
  • 一、資料庫類型 關係資料庫管理系統(RDBMS) 非關係資料庫管理系統(NoSQL) 按照預先設置的組織機構,將數據存儲在物理介質上(即:硬碟上) 數據之間可以做無關聯操作 (例如: 多表查詢,嵌套查詢,外鍵等) 主流的RDBMS軟體:MySQL、MariaDB、Oracle、DB2、SQL Ser ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...