[英]Basic optimisation with an index for mysql
我对基本的MySQL数据库优化有疑问。 我有3个表,文章,标签和标记(这是一个联接表)。
Articles Taggings Tags
id id id
name article_id name
tag_id
我正在使用以下查询检索与指定标签完全匹配的文章
SELECT *, COUNT(*) AS c
FROM articles AS a
JOIN taggings AS tng ON a.id = tng.article_id
JOIN tags AS t ON t.id = tng.tag_id
WHERE t.name IN ("Red","Green")
GROUP BY a.id
HAVING c = 2
这个查询很慢,所以我做了一个EXPLAIN,得到了以下结果:
替代文字http://dl.dropbox.com/u/2306276/EXPLAIN%20results.png
现在,我真的不明白我在这里做什么,但是我认为“类型:全部”不好,因此我想我将在taggings表中的article_id和tag_id中都添加索引(BTREE),然后运行查询再次。 替代文字http://dl.dropbox.com/u/2306276/EXPLAIN%20results%202.png好吧,这对于我没有受过教育的人来说看起来并不好,行数与上一个相同,而且类型仍然是ALL在两种情况下。
那么有人可以告诉我我要去哪里了吗? 索引对这个问题有帮助吗?
我的标签表将保持相对较小,因此我认为查询应扫描标签表以查找我指定的标签,然后(通过索引)能够立即检索关联的属性,而且所有操作都应该非常快,显然我的想法有些错误。
谢谢
[编辑]-对于杰伊的评论
我添加了10k的文章,30k的标签和6个标签,还在tag.name和taggings.tag_id上添加了2个索引,查询仍然花了很长时间才能运行,0.5-1秒,下面是EXPLAIN。 替代文字http://dl.dropbox.com/u/2306276/EXPLAIN%20results%203.png
因为tags.name是唯一真正减少结果集中的行数的列,所以必须对其进行索引以使任何基于标签的搜索查询更快。
更新:尝试运行此查询
SELECT a.*
FROM articles AS a
JOIN taggings AS tng ON a.id = tng.article_id
JOIN tags AS t ON t.id = tng.tag_id
WHERE t.name IN ("Red","Green")
GROUP BY a.id
HAVING COUNT(DISTINCT t.id) = 2
您也可以尝试使用两次联接表而不是GROUP BY。 有时这会产生更快的查询:
SELECT a.*
FROM articles AS a
JOIN taggings AS tng1 ON a.id = tng1.article_id
JOIN tags AS t1 ON t1.id = tng1.tag_id AND t1.name = "Red"
JOIN taggings AS tng2 ON a.id = tng2.article_id
JOIN tags AS t2 ON t2.id = tng2.tag_id AND t2.name = "Green"
这里发生了几件事。
首先,您的表目前非常小。 当表较小时,DBMS通常会发现读取整个内容而不是使用任何索引的速度更快。 为了获得有意义的EXPLAIN结果,您需要在表中获取实际数量的记录。
看起来您已经将“ id”字段声明为主键。 主键是索引的子类,因此它们应该可用。 请注意,解释计划表明它使用主键来查找标签记录。
该查询的明显起点是标签。 因此,如果这是一个重要的查询,我将在Tags(name)上创建一个索引。 这样就无需顺序搜索“标记”表。
从那里应该通过tag_id查找Taggings。 因此,您应该对此有一个索引。
然后可以按article_id查找Article。 那是主键,所以它应该已经在那了。
因此,我认为您将通过两个索引获得最有效的计划:Tags(名称)和Taggings(tag_id)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.