有沒有更好的方法來處理多級 ParentId 表結構?
我在一家出版商工作,我們的產品主要是書籍和期刊。它們最常見的結構如下:
Book > Chapter Book Series > Book > Chapter Book > Volume > Chapter Book Series > Book > Volume > Chapter Journal > Volume > Issue > Article Journal > Volume > Article
我們目前將所有這些記錄儲存在具有 Id 和 ParentId 列的同一個表中。例如,TitleId = 1 的書有 3 個章節,將有以下行:
Book: Id = 1, ParentId = 1 Chapter #1: Id = 2, ParentId = 1 Chapter #2: Id = 3, ParentId = 1 Chapter #3: Id = 4, ParentId = 1
所有這些記錄,無論是書籍、章節、期刊、文章等,都可以將其 ID 連接到其他表,以獲取作者、價格、所有權等資訊。
這種結構給我們帶來的問題是嵌套在某些情況下會增加大量成本。例如,如果有人試圖訪問他們購買的期刊文章,我們需要執行多個查詢以了解他們是否確實有權訪問。我們有一個包含所擁有產品的 Id 的所有權表,因此我們不僅需要檢查使用者是否直接擁有期刊文章的 Id,還需要檢查文章的父期、捲和期刊的 Id 的所有權。(即,如果使用者擁有整個期刊,則暗示他們擁有該期刊中的所有文章,儘管沒有明確的訪問權限。)所以我們的主要“所有權”查詢相當龐大,因為我們需要它來檢查所有權嵌套級別。
類似的情況還有很多。例如,如果我們需要獲取與一本書關聯的所有作者,我們需要直接執行該書的查詢,然後走到每一章並獲取每一章的所有作者,或者如果這本書有捲,我們需要遍歷每卷,並獲得每卷章節的作者。
另一種情況是搜尋,我們需要基本上聚合所有這些不同的類型以被視為相對平等,以便可以對它們執行搜尋,以及結果,無論它們是一本書、章節、期刊、文章等,都需要在搜尋結果中並排出現。
我想知道是否有一種方法可以改進我們的設置,以便我們可以更快地獲取關係數據(例如所有權檢查、作者、價格等),方法是:
- 重構我們的主表以擺脫 Id/ParentId 設置,或者,
- 在旁邊建構新的表/視圖。
我對任何人對我們目前設置或提出新設置的任何評論/建議/建議感興趣。
我將始終儲存中間實體,可能通過將缺少的實體添加為虛擬條目,以便您始終可以使用相同的查詢進行查詢。
例如,商店
書籍>章節
作為
叢書(木偶)>書籍> 卷(木偶)>章節
現在,您可以查詢
SELECT * FROM BookSeries bs LEFT JOIN Book b ON bs.BookSeriesID = b.BookSeriesID LEFT JOIN Volume v ON b.BookID = v.BookID LEFT JOIN Chapter c ON v.VolumeID = c.VolumeID
where
BookSeries
和Volume
將產生 NULL 列,除了主鍵和外鍵。因此,始終以所需級別開始
BookSeries
和結束儲存。所以如果你想儲存一本沒有捲也沒有章節的書,這很好。該查詢將為捲和章節(包括主鍵和外鍵)生成 NULL 列。LEFT JOIN 確保了這一點。期刊有不同的結構。這裡有兩種可能的方法:
- 將日記帳作為獨立層次結構儲存在其他表中。
- (部分)統一兩個層次結構並使用
Type
orKind
欄位作為鑑別器來區分書籍和期刊BookSeries > BookOrJournal > Volume +--> Issue > Article | \--> Chapter
我認為 Olivier 的建議是一個很好的建議。請注意,SQL Server 有一種用於處理層次結構的特殊數據類型,稱為 hierarchyid。從您提供的資訊來看,我沒有看到任何會阻止您使用此數據類型的內容。
您可以在以下位置閱讀更多資訊:- https://docs.microsoft.com/en-us/sql/t-sql/data-types/hierarchyid-data-type-method-reference?view=sql-server-ver15
網上也有很多關於如何儲存層次結構和各種不同技術的討論。
您可以從包含一些經典參考的這篇文章開始
https://www.red-gate.com/simple-talk/sql/performance/the-performance-of-traversing-a-sql-hierarchy/