【问题标题】:Searching objects by multiple tags in minimal time在最短的时间内通过多个标签搜索对象
【发布时间】:2013-11-28 12:18:40
【问题描述】:

我想按标签搜索对象。我想出的第一个方法是以下模型:

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 秒内执行完毕。不知何故,我可以理解扫描一个表比相交操作更快,但这样我就不能使用索引。

我的目标是不吓跑用户的响应时间。

【问题讨论】:

  • 您可以使用索引,只要 '%' 仅在末尾。但这并不是真正的答案......但是,“标签包含所有标签名称”的说法与设计相矛盾。那么,ObjectTag 表的意义何在?
  • @Strawberry 该字段存在其他原因。我列出它是因为我在第二个查询中使用了它。

标签: php mysql search taxonomy tagging


【解决方案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 子句,所以这是一个最好的猜测。

【讨论】:

  • 结果符合我的预期,但执行时间与我的第一个解决方案相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-17
  • 1970-01-01
相关资源
最近更新 更多