1. 程式人生 > >sqlite3樹形結構遍歷效率對照測試

sqlite3樹形結構遍歷效率對照測試

效果 fcm 技術 art 一個點 解析 got log 創建數據庫

sqlite3樹形結構遍歷效率對照測試

一、緣起

項目數據結構:本人從事安防行業,視頻監控領域。項目中會遇到監控點位的組織機構劃分、暫時劃分的巡邏點位等。這些相機點位、連同組織機構,它們在邏輯關系上構成了一個樹形結構。

又因為不論什麽一個點位屬於一個組織機構,也可能屬於一個被暫時創建的視頻巡邏計劃中,因此,能夠看出,不論什麽一個節點,包含相機節點和組織機構節點,都有可能有至少一個父級節點,且不論什麽一個組織機構節點也會有多個下級子節點。這中邏輯關系又構成了圖。
數據量規模:一個市級別的管理平臺,點位數量在十萬至幾十萬級別。一個省級別的管理平臺,所接入的點位規模在百萬級別。

問題:監控平臺常常須要用到的功能,就是要高速查詢出來一個節點下的全部子節點、子節點的子節點等的樹形結構。


我們的數據庫眼下採用的是sqlite3。 眼下須要對查詢遍歷部分做性能上的優化,由我來承擔完畢這項工作。本人無數據庫方面開發的經歷。僅僅用了一天時間嘗試了例如以下4種方案。或許還有最好的。親愛的讀者您看到了這篇帖子,假如知道有更好的方法,還請賜教,筆者不勝感激。
因為一些原因。在這裏不便於公開各個方案的代碼、sql語句、或sqlite表結構等信息。還請諒解。

二、方案

從上面的數據結構能夠看出,要想查詢到一個節點的全部子節點,通常的做法是必須使用遞歸的方法。這就有了方案1、2、3。假設轉換一下思路
。則就產生方案4。

方案1:multimap遞歸查詢 因為每一個節點極其父節點構成一個pair,這恰巧和STL中的multimap的數據模型一致。所以自然考慮到使用multimap實現遞歸遍歷的方案。

詳細例如以下: (1)從數據庫中查詢全部的數據。 (2)將查詢的結果集插入(insert)到multimap中。

(3)用遞歸的方法遍歷查詢到multimap中的節點及全部樹形子節點。
方案2:函數遞歸查詢 方案1是將全部數據都查詢出來,然後在multimap中遞歸查找。方案2的思路是。查找這個節點的子節點,然後查找子節點的子節點,然後查找子節點的子節點的子節點......(子子孫孫無窮匱也)。實現方法是編寫一個遞歸函數,遞歸地查詢數據庫,即遞歸地select。

(1)從數據庫中查詢全部的父節點是“傳入節點”的節點記錄。 (2)從(1)中的結果集中,取出查詢到的節點id,將這個節點作為“父節點”,然後又一次運行(1)。 (3)由(1)和(2),假設某一次遍歷的結果集為空。則表示當前遍歷到的這個節點是葉子節點,它沒有子節點了。

則遞歸函數退出。

方案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樹形結構遍歷效率對照測試