使用多个索引优化MySQL查询

时间:2016-04-28 04:05:07

标签: mysql indexing

我有一个问题:

SELECT items.*
FROM items
INNER JOIN other on other.some_key = items.some_key
WHERE
  items.partition_id = 7 AND
  items.created_date > '2016-01-01 00:00:00' AND
  (
    other.name like '%user query%' OR
    match (fulltext_candidate) against ('+user* +query*' IN BOOLEAN MODE) OR
    items.some_varchar like '%user query%'
  )
ORDER BY items.created_date
LIMIT 20 OFFSET 0;

我添加了多个索引

ALTER TABLE `items` ADD INDEX `partition_id` (`partition_id`)
ALTER TABLE `items` ADD FULLTEXT `fti` (`fulltext_candidate`)
ALTER TABLE `items` ADD INDEX `created_date` (`created_date`)
ALTER TABLE `items` ADD INDEX `some_varchar` (`some_varchar`)
ALTER TABLE `other` ADD INDEX `name` (`name`)

查询很慢。慢查询日志显示查询扫描items表的所有行。我相信MySQL只在查询中使用一个索引。如果我执行简化查询,我在WHERE子句中只包含一列,则查询速度非常快。

如何使用全文和普通索引构建一个优化此查询的索引?

3 个答案:

答案 0 :(得分:0)

这对评论来说太大了。

这看起来很奇怪。

inner join other on other.some_key = items.some_key

我假设some_key已编入索引,但有一个非常奇怪的名字?如果是,并且它没有按照指定命中查询的索引,那么我认为它可能正在进行全表扫描,因为这是获取数据的最快方法。我需要了解更多有关您的数据等方面的帮助。举个例子。在小表中,数据库可能会全表扫描它们,因为它是几千字节的数据,您可以通过多种方式在查询中访问它。优化器查看索引并调用它可以过滤结果集的数量,如果此数字很低则不会使用它。

答案 1 :(得分:0)

我假设您已从查询中删除了一些细节 - " other.some_key"和" items.somekey" (你的连接列)肯定应该编入索引。

5.0之前的MySQL版本每个查询只能使用一个索引。 explain将告诉您在这种情况下发生了什么。

无论您做什么,您的查询中都有一些标准不会使用索引:

other.name like '%user query%' 
items.some_varchar like '%user query%'

有一个领先的通配符,索引对你没有好处(你可以转换为自由文本搜索吗?)。目前还不清楚这导致了多少性能影响 - 如果您的查询的其余部分将匹配记录的数量减少到数百或数千,那么它可能没有什么区别。再次,EXPLAIN将帮助您。

如果你可以删除领先的外卡,并且可以添加" some_varchar"对于复合指数,它应该有所帮助。

对于您的查询,我创建了一个复合索引;这样,优化器就不会猜到你了。

ALTER TABLE `items` ADD INDEX `compound` (some_key, partition_id, created_date)

答案 2 :(得分:0)

<强>答案

有这些;没有其他人对您的查询(或任何讨论的变体)有用:

items: INDEX(partition_id, created_date)
other: INDEX(some_key)
关于所有其他聊天的

评论

ORs阻止使用其中提到的列的索引(例如FULLTEXT)。也就是说,删除前导%仍然无效 - 因为OR

(some_key, partition_id, created_date)使其无法用于WHEREORDER BY

即使您可以使用“索引合并”,也很少被调用,因此不值得考虑。 (而且它只是一个粗糙的绷带。)

如果您有MATCH ...可以使用FULLTEXT索引,则只会使用FULLTEXT索引。也就是说, if 可以使用它。同样,OR会阻止您的情况。当然,“复合”索引非常有用;但优化器总是假设FULLTEXT更有用。

由于无法使用FULLTEXT,优化程序应继续INDEX(partition_id, created_date)并发现它很有用。