2009-10-07 93 views
1

我正在編寫一個PHP/MySQL網站,我想實現一個類似於stackoverflow標記引擎。我在DB 3個相關的表: 1.用品 2.標籤 3. ItemTagMap(地圖標記的項目,N:N映射)現在如何在php/mysql中實現類似SO的標記系統?

,搜索頁面上我想顯示所有的不同列表標記整個搜索結果(而不僅僅是當前頁面),以便用戶可以通過添加/刪除標記列表中的標記來「精煉」他們的搜索。

問題是這是一個非常沉重的數據庫查詢,並且可能會有大量的搜索請求導致不同的結果集和不同的標籤集。

有誰知道如何有效地實現這一點?

+1

在增加要求的風險下,是不是也很好地顯示COUNT每個標籤,對應一個特定的搜索? – mjv 2009-10-07 02:04:53

+0

是的,我會這樣做 - 我甚至統計每個標籤存儲在單獨的表中。 – 2009-10-07 02:11:25

回答

8

在我們進入提前優化模式之前,查看下面的查詢模板可能很有用。如果沒有其他可以用來作爲衡量可能的優化效果的基線。

SELECT T.Tagid, TagInfo.TagName, COUNT(*) 
FROM Items I 
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId 
JOIN ItemTagMap T ON I.ItemId = T.ItemId 
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId 
WHERE I.ItemId IN 
    (
     SELECT ItemId 
     FROM Items 
     WHERE -- Some typical initial search criteria 
     Title LIKE 'Bug Report%' -- Or some fulltext filter instead... 
     AND ItemDate > '02/22/2008' 
     AND Status = 'C' 
) 
--AND T1.TagId = 'MySql' 
GROUP BY T.TagId, TagInfo.TagName 
ORDER BY COUNT(*) DESC 

子查詢是「驅動查詢」,即對應於最終用戶的初始標準的那個。 (請參閱下面有關此查詢的詳細信息,需要多次才能適用於整體優化流程) 註釋爲T1上的JOIN(並且可能在選擇多個標記時T2,T3),並且使用WHERE子句相關標準。當用戶選擇特定標籤時,無論是作爲初始搜索的一部分還是通過細化,都需要這些。 (這可能是更有效的放置這些連接,並且其中所述子查詢中的條款;更多關於這些下文)

討論... 「驅動查詢」,或其變體需要用於兩個不同用途:

  • 1,以提供所需要枚舉所有相關聯的標籤項目Id的完整列表。

  • 2提供前N個ItemId值(N是顯示頁面大小),用於在Item表中查找Item詳細信息。

注意,完整列表不需要進行排序(或者也可以從不同的順序排序中獲益),從而使第二列表需要根據用戶的選擇進行排序(比如按日期,降序或標題,按字母順序升序)。還要注意的是,如果需要任何排序順序,查詢的代價將意味着處理完整列表(由SQL本身避免奇怪的優化,和/或一些非規範化,SQL需要「查看」該列表上的最後記錄,如果它們屬於頂部,按照順序)。

這後一個事實是贊成爲兩個目的有相同的查詢,相應的列表可以存儲在臨時表中。一般流程是快速查找含有詳細信息的前N個項目記錄,並立即將其返回給應用程序。然後,應用程序可以獲取ajax-fashion用於細化的標籤列表。這個列表將產生一個類似於上面的查詢,其中子查詢被替換爲「select * from temporaryTable」。 SQL優化器會決定對此列表進行排序(在某些情況下),讓我們讓它做到這一點,而不是第二次猜測它並明確排序。

另一個要考慮的問題是,可能會將ItemTagMap表上的連接帶入「驅動查詢」中,而不是像上面所示。這可能是最好的,無論是爲了表現,還是因爲它會產生#2目的的正確列表(顯示一頁的項目)。

即使在相對適中的硬件上,上述查詢/流程也可能相當順利;暫定爲1/2 Million +項目,持續的用戶搜索量可能高達每秒10個。其中一個關鍵因素是初始搜索標準的選擇性。

優化思路

  • [根據典型的搜索案件和數據統計]可能是有意義將通過使(確實複製)一些項目字段到ItemTagMap表的非規範化。特別是短的領域可能是'受歡迎的'那裏。隨着數據量在百萬以上的項目中增長,我們可以利用一些標籤(例如:在SO中,PHP通常與MySql一起出現,通常沒有任何理由...)和各種技巧的強關聯。例如,引入「多標籤」TagIds可能會使輸入邏輯稍微複雜一些,但也可能會顯着縮小映射的大小。


- '不說了! -
應根據實際要求和有效的數據統計資料選擇適當的體系結構和優化...

+0

這是一個了不起的帖子,我想你 – y2k 2010-06-04 17:04:11

+0

@Joshua:謝謝你說的客氣話。 – mjv 2010-06-07 07:05:44

+0

這是一個關於數據庫模式的好文章,其中有一個,兩個或三個表,用於不同的架構/性能需求:http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html – ATSiem 2012-03-14 20:21:10

0

假設:

  • 項目(ID);
  • 帶有索引名稱的標籤(id,name);
  • ItemTag(item_id,tag_id)。

則:

SELECT t.name 
FROM Tag t 
WHERE EXISTS (SELECT 1 FROM ItemTag WHERE item_id = 1234) 
ORDER BY t.name 

沒有密集有關。這是類似的,但我的猜測是,這將是更慢:

SELECT t.name 
FROM Tag t 
WHERE t.id IN (SELECT tag_id FROM ItemTag WHERE item_id = 1234) 
ORDER BY t.name 

這是可以做到的加入,以及:

SELECT DISTINCT t.name 
FROM Tag t 
JOIN ItemTag i WHERE i.tag_id = t.id 
WHERE i.item_id = 1234 
ORDER BY t.name 

我第一個想到的會更快,但因爲始終是這種情況使用SQL,值得測試(在足夠大小的數據集上)。

上面已經完成列出單個項目的標籤。您需要一組用於搜索結果的標籤。從上面這不難,但這取決於你如何獲得搜索結果。

+1

我不確定這是否會回答OP。基礎搜索(來自站點用戶)將產生許多item_id值。我懷疑你是否建議應該單獨搜索這些ID中的每一個...... – mjv 2009-10-07 01:53:18

+0

@mvj這是一個簡單的修改,將它帶到該級別。要將標籤與多個項目進行比較,請執行'... WHERE item_id IN(...)...'。此外,爲了縮小結果的標籤,只需添加到子句'... WHERE item_id IN(...)和tag_id IN(...)...' – 2009-10-07 02:44:25

+0

@cletus好的item_id IN(... )部分。然而,基於Tad_Id的縮小將需要多次加入ItemTag表。對 ?    (無關)你如何評論背景顏色?很酷。 – mjv 2009-10-07 03:11:08

0

你會想盡量減少數據庫調用的數量,把繁重的工作放到PHP中。

首先,從數據庫中選擇所有項目:

select * from items where (conditions); 

然後,創建所有的ID從結果集的數組。

$ids = array(); 
foreach ($items as $item) { 
    $ids[] = $item['id']; 
} 
$ids = implode(',' $ids); 

然後爲您以前檢索的項目ID選擇所有ItemTagMaps和相關聯的標籤數據。

select map.item_id, t.id, t.name from tags t, item_tag_maps map where t.id = map.tag_id and map.item_id in ($ids); 

現在,當您通過$ items數組循環,你可以從你執行的,只要它有一個匹配ITEM_ID值二號SQL查詢找到所有匹配的標籤。

+0

做下面的工作效率會更高嗎? select * from項目where(conditions); 從標記TM內選擇t.name聯接item_tag_maps地圖上t.id = map.tag_id WHERE內部聯接上map.item_id = ITEM_ID項目{相同的條件放在這裏......}? – 2009-10-07 02:08:41

+0

此外,即使我要僅顯示一頁數據,您的方法也會從數據庫中檢索項目的整個表格。使用我的方法,我可以添加LIMIT()到第一個選擇帶來最小數據 – 2009-10-07 02:18:46

+0

沒有邁克爾,你錯了。請注意我傳遞給每個SELECT語句的條件。第二個SELECT只檢索在第一個SELECT語句中檢索到的匹配item_id的標籤,並且第一個SELECT語句應該匹配第一個頁面的條件。 – 2009-10-09 15:31:43

相關問題