使用索引改进MySQL表

时间:2011-04-19 14:16:25

标签: php mysql optimization indexing

我对MySQL中的索引很新。我知道,我应该早点把它拿出来,但大多数项目都足够小,我可以逃脱它;)

所以,现在我正在测试它。我通过在查询上运行EXPLAIN来完成测试:

查询:

EXPLAIN SELECT a . *
FROM `tff__keywords2data` AS a
LEFT JOIN `tff__keywords` AS b ON a.keyword_id = b.id
WHERE (
b.keyword = 'dog' || b.keyword = 'black' || b.keyword = 'and' || b.keyword = 'white'
)
GROUP BY a.data_id
HAVING COUNT( a.data_id ) =4 

首先,没有索引我得到了这些结果:

enter image description here

然后,对于data_id和keyword_id的索引,我得到了这个:

enter image description here

据我了解,MySQL必须搜索的行数从61k减少到10k,这一定是好的吗?

所以我的问题是,我在这里是否正确?在尝试优化时还有什么可以考虑的吗?

更新

此外,在AJ和Piskvor的一些帮助指出我的另一个表及其列关键字没有索引后,我得到了这个:

enter image description here

很大改进!正确?

6 个答案:

答案 0 :(得分:4)

如您所见,用于表格key的{​​{1}}仍为b。您可能希望在NULL上添加索引并与

匹配
b.keyword

这在功能上与您的WHERE b.keyword IN ('dog','black','and','white') 子句不同,但它返回相同的结果。

看起来,您可能对全文搜索感兴趣。

答案 1 :(得分:3)

根据您要实现的目标,您应该将LEFT JOIN替换为INNER JOIN,或将WHERE条件移至ON子句:

现在:

SELECT  a.*
FROM    `tff__keywords2data` AS a
LEFT JOIN
        `tff__keywords` AS b
ON      b.id = a.keyword_id
WHERE   b.keyword = 'dog' || b.keyword = 'black' || b.keyword = 'and' || b.keyword = 'white'
GROUP BY
        a.data_id
HAVING  COUNT( a.data_id ) = 4 

您的查询实际上是INNER联接(因为WHERE子句中有非空条件)。

此外,您应该使用原生ORIN构造来代替使用位算术(不可思议):

SELECT  a.*
FROM    `tff__keywords2data` AS a
JOIN    `tff__keywords` AS b
ON      b.id = a.keyword_id
WHERE   b.keyword IN ('dog', 'black', 'and', 'white')
GROUP BY
        a.data_id
HAVING  COUNT(*) = 4 

您可能还想在ttf__keywords (keyword)上创建一个索引,该索引可以对您要搜索的keywords进行过滤,并从前导b中选择较少的记录。

最后,如果您不需要a.data_id上的隐式排序,请通过附加ORDER BY NULL来删除它:

SELECT  a.*
FROM    `tff__keywords2data` AS a
JOIN    `tff__keywords` AS b
ON      b.id = a.keyword_id
WHERE   b.keyword IN ('dog', 'black', 'and', 'white')
GROUP BY
        a.data_id
HAVING  COUNT(*) = 4 
ORDER BY
        NULL

这会从您的计划中移除filesort

答案 2 :(得分:1)

是的,这有所改善(但从快速看,我认为可以更好地改进)。你可以看到,查询优化器现在看到AND USING keyword_id索引。它已经将搜索的行从64283减少到10216.但是这仍然使用一个文件库,希望其他人可以澄清类似于SQL Server表扫描?这不好......但我可能错了。

您现在应该可以将表b中的行减少到10216以下

答案 3 :(得分:1)

你正在对b.keyword进行字符串比较....在那里添加一个索引。

答案 4 :(得分:1)

使用INNER JOIN代替LEFT JOIN。左连接将返回连接表中不匹配的行,我认为您不需要这些行。

答案 5 :(得分:1)

尝试将索引放在WHERE子句中的所有内容中,以及JOIN中的任何内容,这样就可以了:

a.keyword_id 出价 b.keyword

您可能还想尝试向a.data_id添加索引,因为它位于“GROUP BY”中。索引太多通常不是问题,除非您向大型表添加大量数据 - 这可能导致INSERT非常慢。