mysql - 相同的查询,MySQL 5.5 和 5.7 上的执行时间不同。 (MySQL 5.5不使用索引)

标签 mysql sql query-optimization query-performance

出于兼容性原因,我不得不将生产数据库从 MySQL 5.7 降级到 MySQL 5.5。

升级到 5.5 后,我注意到这个查询变得慢得多,执行时间从大约 200 毫秒减少到大约 20 秒。

这是查询:

SELECT
  COUNT(*)
FROM
  `calendar`
INNER JOIN
  `spot` ON `spot`.`product` = `calendar`.`product`
        AND `spot`.`company_id` = `calendar`.`company_id`
INNER JOIN
  `detection` ON `detection`.`spot_id` = `spot`.`id`
WHERE `calendar`.`starts_at` = '2017-11-17'
  AND `calendar`.`user_id` = 73
  AND `detection`.`date` >= '2017-11-17'
  AND `detection`.`date` <= '2017-11-23'

这是 MySQL 5.5 的 EXPLAIN 输出:

1 SIMPLE | calendar | ref starts_at_ends_at_index starts_at_ends_at_index 3 const 1204 | Using where
1 SIMPLE | spot ref PRIMARY,company_id_index,product_index | product_index | 302 calendar.product | 13 | Using where
1 SIMPLE | detection | ref spot_id_index,date_index | spot_id_index 48 | spot.Id | 80 | Using where

这是 MySQL 5.7 的 EXPLAIN 输出:

1 SIMPLE | calendar | ref starts_at_ends_at_index starts_at_ends_at_index 3 const 1204 | Using where
1 SIMPLE | spot ref PRIMARY,company_id_index,product_index | product_index | 302 calendar.product | 13 | Using index condition; Using where
1 SIMPLE | detection | ref spot_id_index,date_index | spot_id_index 48 | spot.Id | 80 | Using where

我能看到的唯一区别是 MySQL 5.7 使用: 使用索引条件;在 product_index 上使用 where,5.5 则不需要。

我尝试通过指定 USE INDEX(product_index) 来强制使用索引,但没有任何改变

有什么建议吗?

编辑:

当前有用的索引:

ALTER TABLE `calendar` ADD INDEX `starts_at_ends_at_index` (`starts_at`, `ends_at`);

ALTER TABLE `spot` ADD INDEX `company_id_index` (`company_id`);

ALTER TABLE `spot` ADD INDEX `product_index` (`product`);

ALTER TABLE `detection` ADD INDEX `spot_id_index` (`spot_id`);

ALTER TABLE `detection` ADD INDEX `date_index` (`date`);

最佳答案

您的查询通过两个相等条件过滤calendar,因此它们应该出现在彼此相同的索引中。然后,它使用 product 列访问另一个表。因此,将这三列合并为一列 compound index 。试试这个:

 ALTER TABLE calendar ADD INDEX user_id_starts_at_product (user_id, starts_at, product);

您的查询对检测执行数据范围过滤,并选择具有特定spot_id值的行。所以试试这个复合索引。

 ALTER TABLE detection ADD INDEX spot_id_date (spot_id, date);

还可以尝试使用相反顺序的列的复合索引,并保留可以提供更好性能的索引。

 ALTER TABLE detection ADD INDEX date_spot_id (date, spot_id);

尝试在 spot 上使用复合索引来涵盖两个过滤条件(出现在 ON 子句中)。

  ALTER TABLE spot ADD INDEX company_id_product (company_id, product);

专业提示:MySQL 通常只能为每个查询(或子查询)的每个表使用一个索引。因此,添加大量单列索引通常并不是使特定查询更快的好方法。相反,添加符合查询要求的复合索引是正确的方法。对于各种数据库版本都是如此。

关于mysql - 相同的查询,MySQL 5.5 和 5.7 上的执行时间不同。 (MySQL 5.5不使用索引),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53261465/

相关文章:

mysql - 使用两个分区是否仍然比没有它们更好?

php - 使用不同的值更新多行 SQL

mysql - 从其他表更新数据库平均值中的字段

mysql - 查找类别和子类别的 SQL 查询

MySql 查询花费大量时间

Android sqlite 和多个查询

用于性能优化的 mysqltuner 报告

php - 从我的 sql 查询中检查表

sql - 在哪里放置存储过程和交换数据库技术?

mysql - 创建表 : You have an error in your SQL syntax near 'order( order_id INT UNSIGNED NOT NULL AUTO_INCREMENT, user_id ' at line 1 时出错