2013-11-28 76 views
0

我想通過標籤搜索對象。我想出了第一種方法是以下模式:在最短時間內通過多個標籤搜索對象

Object(OID, Tags, ...) 
Tag(TagID, Name, ...) 
ObjectTag(OID, TagId) 

領域Tags包含所有標籤名稱。

現在我不僅想通過一個標籤進行搜索,而是通過多個標籤進行搜索。查詢是這樣的:

SELECT `o`.* 
FROM Object o 
    INNER JOIN ObjectTag tag1 ON(o.OID = tag1.OID) 
    INNER JOIN ObjectTag tag2 ON(o.OID = tag2.OID) 
    ... 
    INNER JOIN ObjectTag tagn ON(o.OID = tagn.OID) 
WHERE tag1.TagID = ? AND tag2.TagID = ? AND ... AND tagn.TagID = ? 

我約100K的對象和每個對象的5-20標籤測試這一點,並花了大約30秒以上,因此往往超過PHP的時限。

出於好奇,我還嘗試使用LIKE根據字段標籤進行查詢。

SELECT `o`.* 
FROM object 
WHERE object.tags LIKE '%tag1%' AND object.tags LIKE = '%tag2%' ... 

但是,這個查詢是在10秒內執行的。不知何故,我可以理解,掃描一個表比交叉操作快,但這樣我就不能使用索引。

我的目標是響應時間,不會嚇跑用戶。

+0

只要'%'只在最後就可以使用索引。但這不是真正的答案......但是,「標籤包含所有標籤名稱」這一說法與設計相矛盾。因此,什麼是ObjectTag表的要點? – Strawberry

+0

@Strawberry該字段存在其他原因。我列出它是因爲我在第二個查詢中使用了它。 –

回答

1

我假設您的索引針對第一個示例進行了優化。

而不是你的第一個查詢具有所有這些連接,你試圖加入一次,然後確保每個記錄都有該標籤。請注意,HAVING子句的N值取決於您正在搜索的標籤數量。

SELECT object.keyfield, COUNT(*) 
FROM object 
JOIN objectTag 
    ON object.OID = objectTag.OID 
WHERE objectTag.TagID IN (tag1,tag2,tag3...tagN) 
GROUP BY object.keyfield 
HAVING COUNT(*) >= N 

您沒有給出預期結果集的任何樣本數據。你也沒有明確顯示SELECT條款,所以這是一個最好的猜測。

+0

結果是我的預期,但執行時間與我的第一個解決方案相同。 –