做到在一個完全規範化的方式,你需要這樣的事:
的MEANING_ITEM有以下指標:
- {SITE_ID,MEANING_NO,ITEM_NO} - 爲主鍵自動創建並支持使用給定標籤高效搜索項目。
- {ITEM_NO,SITE_ID,MEANING_NO} - 可以高效地查詢相反的內容:「獲取給定項目的標籤」。
注意:如果您的DBMS支持它,請考慮clustering此表。集羣表中的二級索引可能很昂貴(因爲它們需要包含整個PK的副本並可能導致雙重查找),但在這種情況下,兩個索引都包含相同的字段(因此所有「額外」字段都已存在於次級索引),並且沒有索引之外的字段,因此不需要進行雙向查找。通過聚類,你只需要消除(無用的)表堆,而只剩下兩個B樹。
這種模式具有以下特性:
- 兩個標籤和物品的部位特異性地識別和您查詢默認站點特定的標籤。如果您想查詢標籤名稱而不考慮網站,只需在下面的查詢中從WHERE子句中省略
SITE_ID = ...
即可。由於TAG_NAME處於TAG PK的領先優勢,因此無需額外索引即可有效地滿足無站點查詢。
- 項目不能標記來自「錯誤」網站的標籤。我們使用標識關係,這些關係沿着「菱形」依賴關係的兩個邊緣向下傳播SITE_ID,併合併到「菱形」(在MEANING_ITEM中)的底部,這就是我們保證的原因。
- 標記同義詞有效地表示(在同一站點內具有相同含義的標記被視爲同義詞)。如果我們試圖在標籤上實現M:N自我關係,那麼就沒有可能發生的各種異常情況。
- 由於標籤的含義是特定於站點的,所以同義詞也是站點特定的。
- 意義表是存儲有關標記(如描述)的附加信息的自然地方,它將由所有同義詞共享。
我們將如何處理同義詞傳遞性?如果A,B和C是同義詞,我們只是存儲A-B和B-C,或者我們也存儲A-C?我們如何執行它?如果我們不強制執行它,我們需要某種遞歸查詢來選擇所有依賴關係。我們需要爲每個連接添加一行,浪費空間和性能。
與要獲得項目特定標記的任何,你需要執行一個類似的查詢......
SELECT *
FROM ITEM
WHERE EXISTS (
SELECT *
FROM TAG JOIN MEANING_ITEM ON
TAG.SITE_ID = MEANING_ITEM.SITE_ID
AND TAG.MEANING_NO = MEANING_ITEM.MEANING_NO
WHERE
TAG.SITE_ID = <site id>
AND TAG.NAME IN (<list of tags>)
AND ITEM.SITE_ID = MEANING_ITEM.SITE_ID
AND ITEM.ITEM_NO = MEANING_ITEM.ITEM_NO
)
注:我們完全可以忽略從JOIN到意義上面的查詢 - JOIN所需的所有字段已經在TAG中。
對於有所有特定標記的項目,你需要一些計算,與此類似:
SELECT *
FROM ITEM
WHERE <number of tags> = (
SELECT COUNT(DISTINCT TAG_NAME)
FROM TAG JOIN MEANING_ITEM ON
TAG.SITE_ID = MEANING_ITEM.SITE_ID
AND TAG.MEANING_NO = MEANING_ITEM.MEANING_NO
WHERE
TAG.SITE_ID = <site id>
AND TAG.NAME IN (<list of tags>)
AND ITEM.SITE_ID = MEANING_ITEM.SITE_ID
AND ITEM.ITEM_NO = MEANING_ITEM.ITEM_NO
)
現在這個貌似很多JOIN-ING的,但這種模式是優秀的對於聚簇(又名index-organized)表和covering帶索引的查詢。
您可能需要先考慮實際StackExchange的數據量,然後再出於性能原因考慮對該設計進行非規範化(例如,刪除聯結表並限制每個項目的標記數)。
在任何情況下,在進行任何特定設計之前都要測量實際的數據量。
標籤如何管理?在大多數站點(如StackOverflow)中,用戶可以快速方便地創建標籤。標籤是否與正式類別相同,即嚴格在編輯過程中進行管理,還是他們是特設的,人羣智慧型的東西? – 2012-07-12 17:11:06
與Stack類似,他們只是鍵入單詞。雖然我們可能需要一個最低水平來創建新的 – 2012-07-13 08:55:43