1. 程式人生 > >精讀《手寫 SQL 編譯器 - 效能優化之快取》

精讀《手寫 SQL 編譯器 - 效能優化之快取》

1 引言

重回 “手寫 SQL 編輯器” 系列。這次介紹如何利用快取優化編譯器執行效能。

可以利用 Frist 集Match 節點快取 這兩種方式優化。

本文會用到一些圖做解釋,下面介紹圖形規則:

image

First 集優化,是指在初始化時,將整體文法的 First 集找到,因此在節點匹配時,如果 Token 不存在於 First 集中,可以快速跳過這個文法,在文法呼叫鏈很長,或者 “或” 的情況比較多時,可以少走一些彎路:

image

如圖所示,只要構建好了 First 集,不論這個節點的路徑有多長,都可以以最快速度判斷節點是否不匹配。如果節點匹配,則繼續深度遍歷方式訪問節點。

現在節點不匹配時效能已經最優,那下一步就是如何優化匹配時的效能,這時就用到 Match 節點快取。

Match 節點快取,指在執行時,快取節點到其第一個終結符的過程。與 First 集相反,First 集可以快速跳過,而 Match 節點快取可以快速找到終結符進行匹配,在非終結符很多時,效果比較好:

image

如圖所示,當匹配到節點時,如果已經構建好了快取,可以直接調到真正匹配 Token 的 Match 節點,從而節省了大量節點遍歷時間。

這裡需要注意的是,由於 Tree 節點存在分支可能性,因此快取也包含將 “沿途” Chances 推入 Chances 池的職責。

2 精讀

那麼如何構建 First 集與 Match 節點快取呢?通過兩張圖解釋。

構建 First 集

image

如圖所示,構建 First 集是個自下而上的過程,當訪問到 MatchNode 節點時,就可以收集作為父節點的 First 集了!父集判斷 First 集收集完畢的話,就會觸發它的父節點 First 集收集判斷,如此遞迴,最後完成 First 集收集的是最頂級節點。

構建 Match 節點快取

image

如圖所示,訪問節點時,如果沒有快取,則會將這個節點新增到 Match 快取查詢佇列,同時路途遇到 TreeNode,也會將下一個 Chance 新增到快取查詢佇列。直到遇到了第一個 MatchNode 節點,則這個節點是 “Match 快取查詢佇列” 所有節點的 Match 節點快取,此時這些節點的快取就可以生效了,指向這個 MatchNode,同時清空快取查詢佇列,等待下一次查詢。

3 總結

select a, b, c, d from e 這個語句做測試:

node 節點訪問次數 Frist 集優化 First 集 + Match 節點快取優化
784 669 652

從這個簡單 Demo 來看,提效了 16% 左右。不過考慮到文法結構會影響到提效,對於層級更深的文法、能啟用深層級文法的輸入可以達到更好的效率提升。

4 更多討論

討論地址是:精讀《手寫 SQL 編譯器 - 效能優化之快取》 · Issue #110 · dt-fe/weekly

如果你想參與討論,請點選這裡,每週都有新的主題,週末或週一釋出。前端精讀 - 幫你篩選靠譜的內容。