14

我有一套SQL Server數據庫中使用的分層數據。數據以guid作爲主鍵存儲,parentGuid作爲指向對象直接父項的外鍵。我通過WebApi項目中的實體框架最常訪問數據。爲了使情況稍微複雜一些,我還需要根據這個層次來管理權限,以便應用於父級的權限適用於其所有子級。我的問題是這樣的:分層SQL數據(遞歸CTE vs HierarchyID vs閉包表)

我已經搜遍了所有,不能決定哪個將是最好的處理這種情況。我知道我有以下選擇。

  1. 我可以創建Recursive CTEs公用表表達式(又名RCTE)來處理分層數據。這似乎是普通訪問最簡單的方法,但是我擔心它在用於確定子對象的權限級別時可能會很慢。
  2. 我可以在表中創建一個hierarchyId數據類型字段,並使用SQL Server提供的函數,如GetAncestor()IsDescendantOf()等。這似乎會使查詢變得相當容易,但似乎需要相當複雜的插入/更新觸發器通過插入和移動來保持hierarchyId字段的正確性
  3. 我可以創建一個closure table,它將存儲表中的所有關係。我認爲它是這樣的:父列和子列,每個父 - >子關係將被表示。 (即1-> 2 2-> 3將在數據庫中表示爲1-2,1-3,2-3)。缺點是這需要插入,更新和刪除觸發器,即使它們非常簡單,並且此方法會生成大量記錄。

我已經嘗試過搜索遍地,找不到任何東西給這三種方法之間的任何建議。

PS我也開放給這個問題的任何替代解決方案

+0

請用您正在使用的SQL Server版本標記您的問題。你的疑問傾向於從孩子到父母,還是其他方式?一個RCTE在單個孩子的父母鏈接之後走在樹上應該不會太糟糕。對於所有的孩子來說,其他方式都是緩慢的。 – HABO

+0

我現在無法檢查版本,但會稍後。我認爲儘管它是2008年或更新的。很可能我會更頻繁地得到父母的子女,而不是得到子女的父母 – jp36

+0

我無法添加其他標記,但它是SQL Server 2008 R2。 – jp36

回答

9

我已經使用了所有三種方法。這主要是品味的問題。

我同意表中父子關係的層次結構是最簡單的。移動子樹很簡單,用CTE編寫遞歸訪問很容易。如果您有非常大的樹結構並且您經常訪問分層數據,性能只會成爲一個問題。大多數情況下,當您在表格上有正確的索引時,遞歸CTE速度非常快。

封閉表更像是上述的補充。查找給定節點的所有後代閃電般快,你不需要CTE,只需要一次額外的連接,所以它很甜蜜。是的,記錄的數量爆炸了,但我認爲它不超過深度爲N的樹的N-1倍的節點數量(例如,深度爲5的三級樹需要1 + 3 + 9 + 27 + 81當僅存儲父 - 子關係時爲121個連接,對於閉包表,則爲1 + 3 +(9 * 2)+(27 * 3)+(81 * 4)= 427)。另外,封口表記錄非常窄(至少只有2個整數),幾乎不佔用空間。當新記錄插入到層次結構中時,生成要插入到閉包表中的記錄列表需要一點點的開銷。

我個人喜歡HierarchyId,因爲它真正地結合了上述兩個方面的優點,即緊湊型存儲和閃電般的存取。一旦你建立起來,它很容易查詢並佔用很少的空間。正如你所提到的,移動子樹是有點棘手的,但它是可管理的。無論如何,你真的在​​一個層次結構中移動子樹的頻率如何?有一些鏈接可以找到一些方法,例如:

http://sqlblogcasts.com/blogs/simons/archive/2008/03/31/SQL-Server-2008---HierarchyId---How-do-you-move-nodes-subtrees-around.aspx

主要缺點我發現HIERARCHYID是學習曲線。作爲其他兩種方法,如何使用它並不那麼明顯。我曾經和一些非常聰明的SQL開發人員合作過,他們經常會遇到困難,所以最終你會得到一個或兩個常駐專家來解決其他人的問題。

+3

我最初進入hierarchyId時碰到的兩個缺點是,首先是在插入/更新觸發器中處理批量插入/更新,其次是在C#中通過實體框架使用hierarchyId'd表。你有任何建議或信息處理這兩者之一? 此外,這個答案是非常有幫助的,但我會稍微等一下,然後選擇它來鼓勵其他可能有幫助信息的人。 – jp36

+0

還有另一個缺點,即嘗試在Analysis Services中使用這些類型的關係時遇到,無論選擇哪種方法來表示它們。自連接,循環和hierarchyid在Analysis Services中都不受支持,這意味着您最終必須執行兩種解決方法之一; (1)創建扁平化視圖來表示以這種方式存儲的維度,或者(2)使用SSIS將維度扁平化爲BI數據庫(星形或雪花模式)。每當將新項目添加到層次結構中時,任何解決方法都需要維護。 – JamieSee