我正在构建一个具有项目和标签的系统,在MySQL中具有多对多关系(通过中间表)。随着我的扩展,一个查询变得慢得令人无法接受,但我正在努力提高它的效率。
有问题的查询相当于“选择所有与x相关联的项目的标签”。这是一个非常简化的版本:
SELECT DISTINCT(t.id)
FROM tags t
INNER JOIN items_tags it ON it.tag_id = t.id
INNER JOIN items i ON it.item_id = i.id
WHERE i.type = 10
我在t.id
,item.id
和“it.tag_id, it.item_id
”上拥有唯一的主要索引。我遇到的问题是items_tags表的大小(~1,400,000行),查询需要的时间太长(这里有一件事让我感到困惑的是phpMyAdmin似乎认为查询速度很快 - 它只是将它作为一些ms,但在实践中似乎需要6或7秒)。
我觉得好像有一种方法可以将items_tags表连接到自身以减小结果集的大小(并且可能不需要那个DISTINCT子句),但我无法弄清楚如何。 ..或者,我认为可能有更好的方法来索引事物。任何帮助或建议将不胜感激!
答案 0 :(得分:0)
嗯,为了记录,这里有什么对我有用(尽管如果有人有任何其他建议,我仍然感兴趣)。
有人指出(在上面的评论中 - 感谢@Turophile!)由于items_tags
表中有标签ID,我可以将tags
表格保留下来。我实际上确实需要来自标签表的其他字段(例如名称)(我简化了问题的查询),但我发现从上面的查询中删除标签表并将标签表连接到其结果上的速度明显更快(EXPLAIN
表明它允许扫描更少的行)。这使查询看起来更像这样:
SELECT
tags.id,
tags.name
FROM tags
INNER JOIN (
SELECT DISTINCT(it.tag_id) AS tag_id
FROM items_tags it
JOIN items i ON it.item_id = i.id
WHERE i.type = 10
) it ON tags.id = it.tag_id
这比查询的上一版本快了大约10倍(将平均时间从大约27秒减少到大约2.5秒)。
最重要的是,为items.type
添加一个索引可以进一步改进(将平均时间从大约2.5秒减少到大约1.2秒)。