sqlite3樹形結構遍歷效率對照測試
sqlite3樹形結構遍歷效率對照測試
一、緣起
項目數據結構:本人從事安防行業,視頻監控領域。項目中會遇到監控點位的組織機構劃分、暫時劃分的巡邏點位等。這些相機點位、連同組織機構,它們在邏輯關系上構成了一個樹形結構。
又因為不論什麽一個點位屬於一個組織機構,也可能屬於一個被暫時創建的視頻巡邏計劃中,因此,能夠看出,不論什麽一個節點,包含相機節點和組織機構節點,都有可能有至少一個父級節點,且不論什麽一個組織機構節點也會有多個下級子節點。這中邏輯關系又構成了圖。數據量規模:一個市級別的管理平臺,點位數量在十萬至幾十萬級別。一個省級別的管理平臺,所接入的點位規模在百萬級別。
問題:監控平臺常常須要用到的功能,就是要高速查詢出來一個節點下的全部子節點、子節點的子節點等的樹形結構。
我們的數據庫眼下採用的是sqlite3。 眼下須要對查詢遍歷部分做性能上的優化,由我來承擔完畢這項工作。本人無數據庫方面開發的經歷。僅僅用了一天時間嘗試了例如以下4種方案。或許還有最好的。親愛的讀者您看到了這篇帖子,假如知道有更好的方法,還請賜教,筆者不勝感激。
因為一些原因。在這裏不便於公開各個方案的代碼、sql語句、或sqlite表結構等信息。還請諒解。
二、方案
從上面的數據結構能夠看出,要想查詢到一個節點的全部子節點,通常的做法是必須使用遞歸的方法。這就有了方案1、2、3。假設轉換一下思路方案1:multimap遞歸查詢 因為每一個節點極其父節點構成一個pair,這恰巧和STL中的multimap的數據模型一致。所以自然考慮到使用multimap實現遞歸遍歷的方案。
詳細例如以下:
(1)從數據庫中查詢全部的數據。 (2)將查詢的結果集插入(insert)到multimap中。 (3)用遞歸的方法遍歷查詢到multimap中的節點及全部樹形子節點。方案2:函數遞歸查詢 方案1是將全部數據都查詢出來,然後在multimap中遞歸查找。方案2的思路是。查找這個節點的子節點,然後查找子節點的子節點,然後查找子節點的子節點的子節點......(子子孫孫無窮匱也)。實現方法是編寫一個遞歸函數,遞歸地查詢數據庫,即遞歸地select。
則遞歸函數退出。
方案3:sql語句遞歸查詢
方案1、2的思路都是在sql語句之外遞歸查詢。
假設可以寫出遞歸的sql語句,效果是不是能更好呢?於是有了方案3。簡單來說。方案3是將方案2中用函數實現的"查找子節點的子節點的子節點......"。替換為用sql語句來實現。
關於sqlite3的遞歸語句,請參考我的另外一篇博文《sqlite3-遞歸查詢》。
這裏要註意一下,sqlite3的遞歸語法 with recursive 可能在 其3.7.X 及下面版本號不受支持,可能會提示語法錯誤syntax error。我的sqlite3庫升級到3.8.x之後就能查詢到結果了。
方案4:引入關系表
如今數據庫表的結構例如以下圖所看到的。
它是一種結構化的數據庫表結構。
將節點的id和父節點id都存儲在一個記錄中。
優點是開發時候高速。壞處是,不便於擴展和改動。
說它不便於擴展,是由於假如一個節點有兩個父節點。則一個字段無法滿足。再加一個father_id字段嗎?顯然不現實,由於不知道會有多少個父節點。
說它不便於改動,是由於。假設將多個父節點id都採用格式化都填入father_id字段。則在維護記錄的時候會帶來“拼串和解析串”的步驟,帶來維護上的麻煩。
那麽。能否夠換一種思路,採用面向對象的思維創建數據庫表呢?於是想到了以下的表結構和表關系。
如圖所看到的。添加一個關系表,專門用來存儲節點之間的關系。
將father_id和son_id作為聯合主鍵。
如此一來,節點與節點之間的關系,事實上就相應的是關系表中的一條記錄!一個節點有多少個子節點,關系表中就有多少條記錄。一個節點有多少個父節點。也是這樣。
這樣改造了數據庫表之後。帶來的優點是顯而易見的。
首先是可維護性的提升。
從曾經的解析改動表字段,到如今的插入刪除一條或多條記錄。
其次是開發維護人員對於數據的關系也會理解地更加深刻和清楚。
但不可避免,也有不足之處。
首先是開發的成本。這種表結構和表關系。不利於高速開發。
其次是如今的軟件系統已經用了好幾年。突然改動,可能會造成現場維護上的壓力突然增大。
第三,這種結構。是否滿足業務功能要求的效能,還是個未知數。
三、結果對照
以下給出上述方案1、2、3的測試對照表。
方案1
方案2
方案3
從理論上來講。查詢得到結果的效率是 方案3 > 方案1 > 方案2。
從上面3個表來看,結果的確如期望的那樣。
可是,有些意外的是。方案3中從結果集中獲取下一條記錄這一步驟(即next),太占用時間,居然達到了97%的占比。
從綜合效率上來看,方案1時間最快。其次是方案3,最慢的是方案2。
由於方案2要運行大量的函數遞歸調用。函數棧切換。這是最為耗時的。
sqlite3樹形結構遍歷效率對照測試