TiDB執(zhí)行計劃(二)

接一篇TiDB執(zhí)行計劃(一),上一篇中主要介紹了執(zhí)行計劃中涉及到的算子,今天把執(zhí)行計劃中剩余的東西講完

查詢計劃命令

EXPLAIN命令,可以查看TiDB執(zhí)行sql時的執(zhí)行計劃,用法和mysql一樣,跟上sql即可

EXPLAIN  SQL語句

舉個栗子(脫敏數(shù)據(jù))

執(zhí)行 EXPLAIN

EXPLAIN 
select
  a0_.id,
  a0_.create_time,
  a0_.end_time,
  a0_.flow_id,
  a0_.campaign_id,
  a0_.unit_id,
  a0_.oa_id,
  a0_.org_path_,
  a0_.param,
  a0_.start_time,
  a0_.state,
  a0_.user_type,
  a0_.update_time,
  a0_.user_id
from
  table_a a0_
where
  a0_.campaign_id = 354361236223
  and a0_.user_id = 25325123
  and a0_.user_type = 1
  and a0_.param = '1'
limit
  1000

執(zhí)行計劃結(jié)果

執(zhí)行計劃結(jié)果

執(zhí)行計劃以一個樹形結(jié)構(gòu)展示出來,來說說每一列的含義吧:

  • id 為算子,是執(zhí)行sql時,每一步需要執(zhí)行子任務
  • estRows為每一個子任務預估需要處理的行數(shù)
  • task為子任務執(zhí)行時候所在的位置
  • access-object子任務的對象,比如說表、索引等
  • operator info子任務執(zhí)行時候的一些算是操作日志的信息吧

上一篇文章說了算子,今天來說下執(zhí)行計劃中,剩下這幾個字段estRowstask、access-objectoperator info的含義吧

estRows:為每一個子任務預估需要處理的行數(shù)
這個很容易理解,就直接上栗子了
select
  user_id
from
  tablea a0_
GROUP by
  user_id

這個sql,對于索引列user_id使用了group by,導致了執(zhí)行時需要對所有索引數(shù)據(jù)進行掃描,會出現(xiàn)IndexFullScan算子,執(zhí)行計劃如下:

estRows
  • 因為這個sql的執(zhí)行計劃是,先對于索引列user_id進行了索引數(shù)據(jù)全量進行掃描,使用了IndexFullScan算子,所以IndexFullScan_11這一步的算子的預估行數(shù)estRows是索引列user_id全量數(shù)據(jù)的數(shù)據(jù)量,133270314
  • 這個sql后一步的執(zhí)行是通過IndexReader算子對下層算子的數(shù)據(jù)進行一個聚合,所以IndexReader_13算子的預估行數(shù)estRowsuser_id列 group by以后的數(shù)據(jù),也就是873229.35了
task:為子任務執(zhí)行時候所在的位置
  • 為子任務執(zhí)行時候所在的位置
  • 主要有兩種
  • cop,是指使用TiKV中的Coprocessor執(zhí)行的計算任務,支持大部分函數(shù)(包括聚合函數(shù)和標量函數(shù))、LIMIT操作、索引掃描和表掃描
  • root,是指在TiDB中執(zhí)行的計算任務,一般所有匯聚TiKV/TiFlash上掃描的數(shù)據(jù)或者計算結(jié)果的算子都只能作為roottask在TiDB上執(zhí)行,所有的Join操作都只能作為roottask在TiDB上執(zhí)行
  • TiDB的SQL優(yōu)化的目標之一是將計算盡可能地下推到TiKV中執(zhí)行
舉個栗子

栗子1:聚合查詢栗子,使用COUNT

select
  COUNT(user_id)
from
  tablea a0_

這個sql,對于索引列user_id使用了COUNT函數(shù),導致了執(zhí)行時需要對所有索引數(shù)據(jù)進行掃描,會出現(xiàn)IndexFullScan算子,執(zhí)行計劃如下:

COUNT函數(shù)
  • 對于索引列user_id使用了COUNT函數(shù),先會對索引列user_id進行索引數(shù)據(jù)全量掃描,IndexFullScan_19算子的執(zhí)行位置為 cop[tikv]
  • 后續(xù)執(zhí)行SteamAgg_8算子時候,因為是 聚合函數(shù),也會在 cop[tikv]上執(zhí)行
  • 最終的IndexReader_21算子對下層算子的數(shù)據(jù)進行一個聚合,在root也就是TiDB中執(zhí)行

栗子2:聚合查詢栗子,使用group by

select
  user_id
from
  tablea a0_
GROUP by
  user_id

這個sql,對于索引列user_id使用了group by,導致了執(zhí)行時需要對所有索引數(shù)據(jù)進行掃描,會出現(xiàn)IndexFullScan算子,執(zhí)行計劃如下:

group by
  • 對于索引列user_id使用了group by,先會對索引列user_id進行索引數(shù)據(jù)全量掃描,IndexFullScan_11算子的執(zhí)行位置為 cop[tikv]
  • 后續(xù)執(zhí)行HashAgg_5算子時候,因為是group by,也會在 cop[tikv]上執(zhí)行
  • 最終的IndexReader_13算子對下層算子的數(shù)據(jù)進行一個聚合,在root也就是TiDB中執(zhí)行

栗子3:子查詢栗子,使用索引IN 子查詢,當子查詢?yōu)槿繒r

select
  *
from
  tablea a0_
where
  user_id IN (
    select
      user_id
    from
      tablea
  )

這個sql,對于索引列user_id使用了in,子查詢?yōu)槿頀呙?,所以會導致外層查詢會對索引?code>user_id進行全索引數(shù)據(jù)進行掃描,會出現(xiàn)IndexFullScan算子,執(zhí)行計劃如下:

IN 子查詢
  • 首先,子查詢沒有加條件,是一個全表掃描,看執(zhí)行計劃2的地方,出現(xiàn)了一個TableFullScan_49,由于子查詢是全量數(shù)據(jù),會在cop[tikv]上執(zhí)行
  • 聚合子查詢結(jié)果的TableReader_50會在root也就是TiDB中執(zhí)行
  • 看執(zhí)行計劃1的地方,當外層sql對索引列user_id進行In時候,會對索引列user_id進行全索引數(shù)據(jù)的掃描,IndexFullScan_40會在cop[tikv]上執(zhí)行
  • 同樣1位置的聚合算子IndexReader_42root也就是TiDB中執(zhí)行
  • 最終的HashJoin_22算子對下層算子的數(shù)據(jù)進行一個聚合,在root也就是TiDB中執(zhí)行
access-object: 子任務的對象,比如說表、索引等
這個很容易理解,就直接上栗子了
select
  * 
from
  tablea a1_
where
  a1_.user_id = 123214125

執(zhí)行計劃如下:

TableRowIDScan栗子
  • 看這個sql,是一個通過索引列user_id進行了索引范圍掃描,他的執(zhí)行邏輯是,先通過對于索引列user_id進行了一個范圍掃描,得到所有符合條件的rowId,然后通過rowId掃描表獲得數(shù)據(jù),看執(zhí)行也是,首先在Build端,通過IndexRangeScan算子,對于索引列user_id進行了范圍掃描,掃描到的rowId,在Probe端,在通過TableRowIDScan算子,通過rowId掃描表獲取數(shù)據(jù),最終通過IndexLookUp算子來匯聚最終的數(shù)據(jù)
  • 看這個sql執(zhí)行計劃的access-object
  • 首先在Build端,通過IndexRangeScan_8(Build)算子,對于索引列user_id進行了范圍掃描,所以該算子的對象是table:a0_,index:idx_user_id(user_id),意思為操作的對象是表a0_的索引idx_user_id(user_id)
  • 然后通過范圍掃描索引得到的rowId掃描表獲得數(shù)據(jù),所以TableRowIDScan_9(Probe)算子的操作對象是表a0_
operator info: 子任務執(zhí)行時候的一些算是操作日志的信息
這個很容易理解,基本是每一步的操作日志,就不舉栗子說明,從原來的栗子中都可以看的懂

TiDB執(zhí)行計劃中的算子就為大家說到這里,歡迎大家來交流,指出文中一些說錯的地方,讓我加深認識。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容