TiDB 優化器實現的基礎:統計資訊的收集
> 收集統計資訊的意義 一個 SQL 資料庫裡,優化器實現的好壞對效能的影響是決定性的。一個未經優化的執行計劃和經過充分優化後的執行計劃,執行時間的差別往往是成千上萬倍。而對一個 SQL 優化器來說,統計資訊是必不可少的條件,只有依賴統計資訊提供的資料,優化器才可以正確估算不同的執行計劃的執行代價,以選擇最優的執行計劃。就像一個大廚無論多麼優秀,沒有上等食材也是無法做出美味的飯菜。
### 統計資訊包含的內容 統計資訊有兩類,包括 Table 統計資訊和 Column 統計資訊。 Table 統計資訊包含 Row Count 和 Row Size。 Column 統計資訊包含 Null Count,Max Value,Min Value,Distinct Count 以及 Histogram。其中 Histogram 用來記錄這個 Column 的資料詳細分佈,可以用來估算大於、小於或等於某個 Value 的 Row Count。 ### 統計資訊採集的步驟 1)在 TiDB 執行 ANALYZE TABLE 語句,手動觸發收集動作。 我們知道,一個 Table 的資料往往是在不斷變化的,我們無法保證統計資訊時刻保持在最新狀態,總會有一定的誤差,如果我們不及時更新,隨著時間的推進,這個誤差可能會越來越大,影響到優化器的優化效果。 有時我們會需要讓統計資訊更新的頻率低一些來降低系統的壓力,因為每次的統計資訊收集都是開銷很大的操作。有時我們會需要立即更新統計資料,因為我們剛剛向一個表匯入了大量的資料,馬上就需要查詢。 所以定期更新統計資訊的功能,我們希望可以用獨立的模組,用更靈活的策略來實現,TiDB 本身只需要支援基本的手動觸發就可以了。
2)全表掃描。 全表掃描的執行過程比較長,整個掃表的任務會被分解為一系列 Region 的小請求,每個 Region 的請求會返回該 Region 包含的 Table 的部分資料。
3)用掃描得到的資料,記錄 Row Count 和 Row Size,並對資料取樣。 掃描得到的資料量有可能會非常大,以至於無法把全部資料保留在記憶體裡進行處理,所以需要進行取樣,當取樣的概率均勻的時候,計算生成的統計資訊的誤差是可以接受的。這裡我們設定的取樣數是 1 萬,無論 Table 有多大,最後保留的樣本數不會超過 1 萬。後面會詳細介紹取樣時使用到的演算法。
4)取樣資料生成 Column 統計資訊,並儲存到 KV。 取樣得到的資料會進行計算生成 Histogram。
取樣演算法
要得到一個均勻分佈的取樣池,一個最簡單的演算法是,當我掃描整個表的時候,讀到的每一行,都以一個固定的概率決定是否加入取樣池,這個概率 P =(取樣池大小/表的行數)。但是由於在掃描之前,我們並不知道一個表總共有多少行,所以如果使用這個演算法進行取樣,就需要掃描兩次,第一次獲取整個表的行數,第二次進行真正的取樣。 一個更優化的演算法,蓄水池演算法,可以在表的大小未知的情況下,一次掃描得到均勻分佈的取樣池。
演算法的實現 假如我們的樣本池大小為 $M = 100$ ,從頭開始掃描全表,當我們讀到的記錄個數 $K < 100$ 時,我們把每一條記錄都加入取樣池,這樣保證了在記錄總數小於取樣池大小時,所有記錄都會被選中。 我們繼續掃描,當我們掃描到的第 $K = 101 條 $ 時,我們用概率 $P = (M/K) = (100/101)$ 決定是否把這個新的記錄加入取樣池,如果加入了取樣池,取樣池的總數會超過 $M$ 的限制,這時我們需要隨機選擇一箇舊的取樣丟掉,保證取樣池大小不會超過限制。 執行這樣取樣演算法一直到全表掃描結束,我們可以得到一個均勻分佈的取樣池。
演算法的證明 這個演算法可以用歸納法來證明,如果表的大小 $N <= K$,所有記錄都會放入取樣池,滿足均勻分佈的要求。 現在假設當讀取完 K 個元素時,取樣池滿足均勻分佈的要求,取樣概率 $P = (M / K)$,當讀取第 $K + 1$ 個記錄時,我們應用蓄水池演算法,以 $P' = M / (K + 1)$ 的概率決定是否加入取樣池,這時出現了兩種情況,被加入和沒有被加入,我們繼續分析這兩種情況下,這條記錄被選中的概率。 如果記錄沒有被選中,舊樣本被保留概率是 $Po1 =(1 - P') P = (1 - M / (K + 1)) (M / K)$, 新樣本被保留的概率是 Pn1 = 0。 如果記錄被選中,取樣池中已有的取樣有 (M - 1) / M 的概率被保留,舊樣本概率是 $Po2 = P' P Po = (M / (K + 1)) (M / K) ( (M -1) / M)$,新樣本的整體概率是 $Pn2 = P' = M / (K + 1)$。 把兩種情況下的概率相加, 得到舊取樣被保留的概率 $Po = Po1 + Po2 = (1 - M / (K + 1)) (M / K) + (M / (K + 1)) (M / K) *( (M -1) / M) = M / (K + 1)$,新取樣被保留的概率為 $Pn = Pn1 + Pn2 = 0 + M / (K + 1) = M / (K + 1)$,所有采樣被保留的概率都是 $M / (K + 1)$,滿足均勻分佈的要求。
Histogram
Histogram 的型別主要有兩種,Frequency Histogram 和 Height-Balanced Histogram。 當 $NDV < Bucket Count$ 時,Frequency 可以包含全部 value 分佈資訊,每一個 distinct value 佔用一個 bucke。 但是當 $NDV > bucket count$ 時,Frequency Histogram 沒有足夠的 bucket 存放 value,我們就需要用另外的 Histogram 型別,比如 Height-Balanced Histogram。 Height-Balanced Histogram 把所有 value 從小到大排序,平均放到所有 bucket 裡,但是缺點是無法記錄有哪些 popular value。 Oracle 還實現了一種 Hibrid Histogram,綜合了 Frequency Histogram 和 Height-Balanced Histogram 的優點,TiDB 實現的 Histogram 主要參考的就是 Oracle 的 Hibraid Histogram。 Hibrid Histogram 包含 N 個 bucket,我們設定的 N 的預設值是 256,每個 bucket 包含三個欄位 number
,value
和 repeat
,number
代表放在這個 bucket 裡的最後一個 value 在 table 裡排序後的 offset,value
就是放在這個 bucket 裡的最大的那一個 value,repeat
代表最大的 value 的個數。 Hibrid Histogram 在生成的過程中,如果一個 bucket 裝滿了,遇到下一個 value 的時候,比較一下這個新的 value 和前一個 value 是否相等,如果相等,增加 repeat 值,直到遇到一個更大的 value,換下一個 bucket 存放這個 value,這樣保證任何一個 value 只會在 一個 bucket 記憶體在,相比 Height-Balanced Histogram,可以包含更準確的 value 分佈資訊。 我們用一個例項來說明 Hibrid Histogram 是如何儲存 value 分佈資訊的。 給定 value 集合 $['a', 'a', 'b', 'c', c', 'c', 'c', 'd', 'd', ‘e’]$ 和 bucket count 3,生成的 histogram 如下:
>[number, value, repeat] [2, 'b', 0] [6, 'c', 3] [9, 'e', 0]
我們可以看到這個集合內, 'c' 的個數有 4 個,在第二個 bucket 裡準確記錄了 'c' 的 repeat 數量 3,這樣我們在查詢條件為 where column = 'c'
的時候,就可以準確的估算執行開銷。 統計資訊的收集,使 TiDB 的優化器掌握資料分佈詳情,準確估算執行開銷,從而實現高效的 CBO (cost base optimization)。
這是對 PingCAP 第 15 期 NewSQL Meetup 中《TiDB 優化器統計資訊的採集》這一議題的乾貨整理。
作為一個前沿領域的技術公司,PingCAP 希望能為在國內營造真正關注技術本身的社群和 Meetup 貢獻一分力量。自2016年3月5日開始 ,我們在每週六舉辦 NewSQL Meetup,通過 1-2 個議題與大家交流討論,並跟大家分享 TiDB 最新的一些進展和我們的思考,希望藉由這個機會讓更多人關注到下一代分散式資料庫。同時,我們也會定期從 Meetup 分享中篩選議題以文章形式與大家做進一步深度探討。歡迎感興趣的小夥伴關注 TiDB 專案,盼望各路大牛加入 PingCAP。
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 基於Python的滲透測試資訊收集系統的設計和實現Python
- MySQl 配置InnoDB持久化的優化器統計資訊MySql持久化優化
- 【統計資訊】Oracle常用的收集統計資訊方式Oracle
- 微課sql最佳化(3)、統計資訊收集(2)-如何收集統計資訊SQL
- 手動收集——收集統計資訊
- 【DBMS_STATUS】Oracle控制優化器統計資訊的使用Oracle優化
- 收集統計資訊方案
- Oracle收集統計資訊Oracle
- Oracle統計資訊的收集和維護Oracle
- TiDB 查詢優化及調優系列(一)TiDB 優化器簡介TiDB優化
- 微課sql最佳化(8)、統計資訊收集(6)-統計資訊查詢SQL
- 收集全庫統計資訊
- [統計資訊系列7] Oracle 11g的自動統計資訊收集Oracle
- 【STATS】Oracle匯入匯出優化器統計資訊Oracle優化
- 基於ctfshow的資訊收集思路與CTF實戰
- 6 收集資料庫統計資訊資料庫
- 1、域滲透基礎簡單資訊收集
- TiDB與MySQL優化器對照TiDBMySql優化
- 深入瞭解 TiDB SQL 優化器TiDBSQL優化
- ORACLE19c新特性-實時統計資訊收集Oracle
- 【TUNE_ORACLE】定製化收集統計資訊SQL參考OracleSQL
- oracle 統計資訊檢視與收集Oracle
- SQL優化之統計資訊和索引SQL優化索引
- MySQL 配置InnoDB配置非持久優化器統計資訊引數MySql優化
- 基於java的大學生健康資訊管理系統的設計與實現Java
- Nebula Graph 特性講解——RocksDB 統計資訊的收集和展示
- Oracle優化案例-統計資訊對執行計劃的影響(十三)Oracle優化
- Oracle運維指令碼-收集統計資訊Oracle運維指令碼
- linux系統基礎的優化以及常用命令Linux優化
- TiDB 效能分析&效能調優&優化實踐大全TiDB優化
- Flink 熱詞統計(1): 基礎功能實現
- TiDB 查詢優化及調優系列(二)TiDB 查詢計劃簡介TiDB優化
- 基於Linux許可權提升的資訊收集Linux
- 最佳實踐:解讀GaussDB(DWS) 統計資訊自動收集方案
- 微課sql最佳化(2)-為什麼需要收集統計資訊SQL
- 基於jsp學生資訊管理系統的設計與實現(含原始檔)JS
- 現代通訊技術基礎中的基礎
- [20200819]12c Global Temporary table 統計資訊的收集的疑問.txt
- 啟用與禁用統計資訊自動收集