每天10分鐘,用去食堂吃飯的時間解決一個知識點。
今天的内容相對來說清湯寡水一點,就梳理下優化器(optimizer)的内容。沒什麼複雜的。
資料庫拿到我們給的SQL後,會解析成一棵文法樹。而優化器做的事情,就是應用關系代數的知識,找出等價的多種計算路徑(即對這棵樹進行數學上等價的變換)。這個過程就是我們标題中的查詢優化。
那麼要衡量不同方案的好壞,就需要我們設計一個代價的評價标準,這就是代價模型。而優化的思路可以分基于代價和基于規則兩種。
基于代價需要我們掌握資料庫中的統計資訊,比如表中的記錄數,記錄的大小,某個字段中不同取值的數目(即選擇性的高低)等。MySQL8.0中會加入直方圖。
基于規則就是變換執行計劃時,有一些啟發式規則。比如盡早執行選擇操作,盡早執行投影操作,避免笛卡爾積等。指導思想就是盡早的縮減規模。
好,這一塊基本上就這些要點了。我感覺抓住指導思想就顯得很清晰,當然去細究細節的話也會很有意思,比如MySQL的代價模型是怎麼算的,我以前聽姜承堯說他覺得MySQL 5.7的代價模型有個bug,這個有興趣可以一起看看源代碼。
順便複習下做等值JOIN時不同的連接配接方式與代價,通過粗略的估算給大家一個直覺的認識。
假設我們有s和t兩張表,現在要做JOIN。s表的記錄數設為5000,占據的塊數設為100;t表的記錄數設為10000,占據的塊數設為400。
就是最簡單的,以一張表的每一行記錄,與另一張表的每一行記錄比較。直接來兩層for循環。我們來估算下代價。
若從s表的每行記錄出發,那麼最壞情況下,塊傳輸次數是5000×400+100=2000100,搜尋次數是5000+100=5100。
若從t表的每行記錄出發,那麼最壞情況下,塊傳輸次數是10000×100+400=1000400,搜尋次數是10000+400=10400。
一個小小的優化思路是,我每次以塊的方式處理關系,這樣不就可以減少塊讀寫次數了麼。
若從s表的每塊出發,最壞情況下,塊傳輸次數是100×400+100=40100,搜尋次數是2×100=200。與前面相比,思路上小小的變化造就了性能上大大的提升。
如果連接配接的字段上有B+樹索引,設每個節點有20個索引項,t表記錄數為10000,那麼樹的高度就是4,回表假設再加一次磁盤IO,此時通路次數為100+5000×5=25100,每次通路都有一次搜尋和一次塊傳輸。咦,怎麼用了索引反而代價更高了?大家注意下,這裡隻說了t表上有索引,如果s表上也有索引且有個選擇操作的話,行數會大大減少。使用索引會比塊嵌套要快得多得多。
好,今天就到這裡。