如何優化大表的連線查詢 如何測試資料庫查詢優化器

2021-10-11 17:17:57 字數 3815 閱讀 2605

我一直認為,查詢優化器(query optimizer,後面簡稱優化器)一直是資料庫領域 top 級別的 hardcore 技術,自己也一直嘗試去深入理解,但每每看到 tidb **裡面那一大坨 plan 的**,我就望而生畏了,就像是『可遠觀而不可褻玩焉』。但雖然很難理解,還是能通過方式去理解優化器的,乙個最直觀的做法就是生成不同的 query 去驗證優化器的效果,實際在 pingcap 內部,我們也是通過 fuzz, a/b testing 等技術,來驗證優化器是否出現效能問題這些。

但無論怎樣,優化器的驗證和測試工作是一件非常難的事情,畢竟對於一條 query,資料庫可能會生成非常多的查詢計畫(plan),我們當然可以通過窮舉的方式找到最優的一條 plan,但實際中,我們只能在有限的時間內找到乙個比較優的 plan。那麼我們如何能確定優化器找到的是一條比較好的 plan 呢?自然需要有一些評價標準,最近看了幾篇 *****,剛好在這個上面做了研究,也對我們後續測試的改良提供了一些方向吧。

首先是 optmark: a toolkit for benchmarking query optimizers 這篇 *****,裡面提到了驗證優化器的兩個指標 - effectiveness 和 efficiency。對於 effectiveness 來說,它主要是衡量優化器對於某條 query 生成的 plan 的質量,而 efficiency 則是衡量生成的 plan 的資源消耗。

effectiveness 主要有兩個指標,乙個是 performance factor,乙個則是 optimality frequency,performance factor 計算公式如下:

對於任何 query q 以及優化器 od 來說,pf 衡量的是在搜尋空間裡面的 plans,比優化器選擇的 plan 要差的比例。od(q)是優化器對於 q 生成的 plan,pd(q)則是所有可能被執行的 plan,r(d, p)則是 plan p 執行的時間,而r(d, od(q))則是優化器選擇的 plan 執行的時間。有了 pf,我們就能得到 optimality frequency,如果 pf = 1,就表明優化器找到了一條相對不錯的 plan。

當然,實際中我們很難將搜尋空間全部遍歷出來,所以通常我們都只是會找足夠多的 plan,***** 裡面提到了 sample size 的概念,也就是會有乙個信心指數的計算,直白的說,就是如果我們需要有 x% 的信心,以及 y% 的精確度來計算 pf,那麼就需要生成 n 個 plans 這種,具體的計算方法可以參考** 2.1.2 章節。

要驗證 effectiveness,**使用了如下方式:

對於 efficiency 來說,**並沒有用傳統的衡量執行時間的方式,而是選用了 4 個指標:

**裡面將這些指標直接加到了 mysql 和 pg 的**裡面進行統計,這個也就是開源的好處了,能直接改**,後面也可以試試 tidb。

總的來說,optmark 這篇 ***** 從 effectiveness 和 efficiency 兩個維度來告訴我們如何測試乙個資料庫的查詢計畫,而且也比較容易實施。不過,在測試 effectiveness 生成 plan 的時候,其實我有點懷疑資料庫到底會不會按照這條 plan 去執行。

在前面那篇 ***** 裡面,optmark 使用的是一種 random join ordering 的方式來對一條 query 進行 join 的順序變換,然後對 join 的 table 選擇不同的 join 演算法,以及對每個 table 使用不同的查詢方式,那麼有沒有其他的辦法來對一條 query 生成執行計畫,並且讓資料庫執行呢?

然後剛好看到了一篇不錯的 *****, counting, enumerating, and sampling of execution plans in a cost-based query optimizer ,其中提到了乙個很不錯的方式,就是通過 memo 這種資料結構,來建立好數字和 plan 的對應關係,我們只要給出乙個數字,就能執行對應的 plan。

首先,對於一條 query,我們可以有乙個非常簡單的 plan,並且用這個 plan 來生成 memo 結構

當生成 memo 之後,我們就可以對 logical operators 進行變換,乙個轉換規則可以是:

在同乙個 group 裡面的 logical operator,譬如join(a, b) -> join(b, a)在同乙個 group 裡面的 physical operator,譬如join -> hash join一組能連線多個 sub plan 的 logical operators,譬如join(a, join(b, c)) -> join(join(a, b), c)

然後做完轉換之後,memo 表現就更豐富了,如下:

最後一項預備工作,就是抽出所有的 physical operators,並且具現化這個 operators 和它們的可能 children 的連線,如下:

當做完了如上三個步驟,就可以通過 memo 這個資料結構算出來總的 query plans,演算法可以直接看 ***** 3.2 章節,其實就是自下而上遍歷每個可能 plan 的個數並且彙總。當我們得到了總的 plan 個數,就可以通過 unranking 演算法知道某個 position 上面對應的 plan,具體的 unranking 演算法可以參考 3.2。當構造了這些資訊之後,我們就可以在 query 裡面直接指定使用某個 plan 了,如下:

其實這個方式非常的巧妙,現在 tidb 是不支援的,沒準可以試試支援下,應該也不困難。

除了上面兩篇 *****,還看了一篇,testing the accuracy of query optimizers,講的是如何測試優化器的精確度,其實就是乙個 estimate time 和實際 execution time 的 pair 對比吧,會計算乙個相關性 score,類似如下:

可以看到,上面 4 個 plan,p1 和 p2 其實明顯會比 p3 和 p4 要好。

然後 ***** 的作者做了乙個 taqo 系統,如下:

流程比較通俗易懂,不多做解釋了,反正可以結合上面第一篇 *****,來驗證優化器的效果吧。

上面列了幾篇,我們當然是想應用到 tidb 來驗證優化器的效果的,當然另外,我們也可以通過讓優化器強制使用不用的 plan,來看優化器會不會有 bug,譬如對於第二篇 *****,沒準我們使用 plan 8 得到的值跟 plan 9 不一樣,這事情就有意思了。

總的來說,優化器這個方向是乙個非常 hardcore 的東西,不光是測試上面,還包括如何實現乙個高效的優化器上面,我們需要非常多的技術儲備,如果你對這方面感興趣,歡迎聯絡我 [email protected]

jitter 如何優化網路 如何優化網路連線

1 遮蔽網路共享功能 要是我們的計算機並沒有處於單位區域網網路中,那麼已經被啟用的網路共享功能其實一點用處都沒有,它的存在反而會拖累系統的啟動速度 要想盡可能地提高系統啟動速度的話,我們完全可以將本地系統已經啟用的網路共享功能給遮蔽掉,下面就是具體的遮蔽操作步驟 首先在windows系統 開始 選單...

如何通過優化測試流程,優化測試時間?

準備工作 1.明確需求 3個思考方向 a.ui頁面上增加了哪些資料 b.每個頁面都包含哪些功能 c.梳理功能,1個功能出現在哪幾個頁面 便於設計可復用的測試用例 2.設計用例,2個思考方向 a.1條用例連貫盡可能多的頁面 b.執行的順序 先驗證異常,再驗證正常功能操作 3.設計測試資料 a.邊界值資...

線上千萬級大表排序該如何優化?

前段時間應急群有客服反饋,會員管理功能無法按到店時間 到店次數 消費金額 進行排序。經過排查發現是sql執行效率低,並且索引效率低下。遇到這樣的情況我們該如何處理呢?今天我們聊一聊mysql大表查詢優化。商戶反饋會員管理功能無法按到店時間 到店次數 消費金額 進行排序,一直轉圈圈或轉完無變化,商戶要...