2013-11-28 39 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

结果是我的预期,但执行时间与我的第一个解决方案相同。 –