Mysql 5.7 不使用索引
Mysql 5.7 dont use index
您好,我从 mysql 5.5 更新到 percona 5.7
这个查询:
SELECT COUNT(a.alarm_id) AS `count`, MAX(a.alarm_id) AS `max_alarm_id`, `a`.`priority`
FROM `alarm` AS `a`
WHERE (a.maintenance_suppress = '0')
AND (a.deleted_at = '0000-00-00 00:00:00')
AND (a.object_id = '6')
GROUP BY `a`.`priority`
不会再按预期使用索引。
这是查询的解释:
+----+-------------+-------+------------+------+---------------------------------------------------------------------+-----------+---------+-------------------+------+----------+--------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------------------------------------------------------------+-----------+---------+-------------------+------+----------+--------------------------------------------------------+
| 1 | SIMPLE | a | NULL | ref | maintenance_suppress,alarm_count,deleted_at,object_id,alarm_count_b | object_id | 10 | const,const,const | 1 | 100.00 | Using index condition; Using temporary; Using filesort |
+----+-------------+-------+------------+------+---------------------------------------------------------------------+-----------+---------+-------------------+------+----------+--------------------------------------------------------+
这是我的索引:
Keyname Type Unique Packed Column Cardinality Collation Null
PRIMARY BTREE Yes No alarm_id 1156170 A No
quited_by BTREE No No acknowledged_by 78 A Yes
deleted_by BTREE No No deleted_by 9 A Yes
device_id BTREE No No component_id 820 A Yes
message_status_create BTREE No No message_status_create 2 A No
leaved_at BTREE No No leaved_at 597481 A No
message_status_leaved 527117 A No
acknowledged_at BTREE No No acknowledged_at 139029 A No
message_status_acknowledged 176719 A No
maintenance_suppress BTREE No No maintenance_suppress 1 A No
ticket_id BTREE No No ticket_id 1 A Yes
alarm_count BTREE No No priority 5 A No
specified_class 8 A No
maintenance_suppress 8 A No
deleted_at 27340 A No
object_id 21310 A No
deleted_at BTREE No No deleted_at 29538 A No
specified_class BTREE No No specified_class 2 A No
created_at BTREE No No created_at 876796 A No
object_id BTREE No No object_id 192 A No
deleted_at 10261 A No
maintenance_suppress 56175 A No
alarm_count_b BTREE No No priority 6 A No
maintenance_suppress 9 A No
deleted_at 31421 A No
object_id 46226 A No
如果我强制索引它会变慢:
mysql> SELECT COUNT(a.alarm_id) AS `count`, MAX(a.alarm_id) AS `max_alarm_id`, `a`.`priority`
-> FROM `alarm` AS `a`
-> WHERE (a.maintenance_suppress = '0')
-> AND (a.deleted_at = '0000-00-00 00:00:00')
-> AND (a.object_id = '68')
-> GROUP BY `a`.`priority`;
+-------+--------------+----------+
| count | max_alarm_id | priority |
+-------+--------------+----------+
| 8 | 1278404 | 2 |
+-------+--------------+----------+
1 row in set (0.01 sec)
mysql> SELECT COUNT(a.alarm_id) AS `count`, MAX(a.alarm_id) AS `max_alarm_id`, `a`.`priority`
-> FROM `alarm` AS `a` FORCE INDEX (alarm_count_b)
-> WHERE (a.maintenance_suppress = '0')
-> AND (a.deleted_at = '0000-00-00 00:00:00')
-> AND (a.object_id = '68')
-> GROUP BY `a`.`priority`;
+-------+--------------+----------+
| count | max_alarm_id | priority |
+-------+--------------+----------+
| 8 | 1278404 | 2 |
+-------+--------------+----------+
1 row in set (0.67 sec)
有人知道我的索引有什么问题吗?
SQL fiddle 玩转:
http://sqlfiddle.com/#!9/23949/1
怀疑升级可能产生影响的原因是它在升级时进行了分析 TABLE,因此现在从更新的统计信息中选择一个索引。
它现在使用的索引对于 WHERE 子句中的列似乎更合乎逻辑。索引中的所有 3 列都在 WHERE 子句中使用。 alarm_count_b 索引在索引的开头有用于 GROUP BY 的列,但这只有在记录被 WHERE 子句排除后才真正有用。
然而,尝试在 object_id 索引的末尾添加优先级作为额外列。
你还没说 5.5 和 5.7 有什么区别。无论如何,您没有最佳索引,所以我将改为回答该问题。
WHERE (a.maintenance_suppress = '0')
AND (a.deleted_at = '0000-00-00 00:00:00')
AND (a.object_id = '6')
GROUP BY `a`.`priority`
以任何顺序请求 INDEX(maintenance_suppress, deleted_at, object_id, priority)
,除了 priority
必须是 last。建议您将 priority
添加到 INDEX object_id
。
作为一般规则,从开始=
条件,然后移动到一个范围条件在WHERE
.如果WHERE
完成,那么一个范围可以是GROUP BY
或ORDER BY
的所有字段。
More discussion of index building.
另一个注意事项。假设您正在使用 InnoDB,alarm_id
将成为该索引的一部分,从而使其成为 "covering"。这提供了额外的提升。 alarm_count_b
也覆盖了,但是列没有按最佳顺序排列,因此性能不佳。
没有看到你的其他查询,我无法判断你的其余索引,只能说 14 个索引是 "a lot"。
您好,我从 mysql 5.5 更新到 percona 5.7
这个查询:
SELECT COUNT(a.alarm_id) AS `count`, MAX(a.alarm_id) AS `max_alarm_id`, `a`.`priority`
FROM `alarm` AS `a`
WHERE (a.maintenance_suppress = '0')
AND (a.deleted_at = '0000-00-00 00:00:00')
AND (a.object_id = '6')
GROUP BY `a`.`priority`
不会再按预期使用索引。
这是查询的解释:
+----+-------------+-------+------------+------+---------------------------------------------------------------------+-----------+---------+-------------------+------+----------+--------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------------------------------------------------------------+-----------+---------+-------------------+------+----------+--------------------------------------------------------+
| 1 | SIMPLE | a | NULL | ref | maintenance_suppress,alarm_count,deleted_at,object_id,alarm_count_b | object_id | 10 | const,const,const | 1 | 100.00 | Using index condition; Using temporary; Using filesort |
+----+-------------+-------+------------+------+---------------------------------------------------------------------+-----------+---------+-------------------+------+----------+--------------------------------------------------------+
这是我的索引:
Keyname Type Unique Packed Column Cardinality Collation Null
PRIMARY BTREE Yes No alarm_id 1156170 A No
quited_by BTREE No No acknowledged_by 78 A Yes
deleted_by BTREE No No deleted_by 9 A Yes
device_id BTREE No No component_id 820 A Yes
message_status_create BTREE No No message_status_create 2 A No
leaved_at BTREE No No leaved_at 597481 A No
message_status_leaved 527117 A No
acknowledged_at BTREE No No acknowledged_at 139029 A No
message_status_acknowledged 176719 A No
maintenance_suppress BTREE No No maintenance_suppress 1 A No
ticket_id BTREE No No ticket_id 1 A Yes
alarm_count BTREE No No priority 5 A No
specified_class 8 A No
maintenance_suppress 8 A No
deleted_at 27340 A No
object_id 21310 A No
deleted_at BTREE No No deleted_at 29538 A No
specified_class BTREE No No specified_class 2 A No
created_at BTREE No No created_at 876796 A No
object_id BTREE No No object_id 192 A No
deleted_at 10261 A No
maintenance_suppress 56175 A No
alarm_count_b BTREE No No priority 6 A No
maintenance_suppress 9 A No
deleted_at 31421 A No
object_id 46226 A No
如果我强制索引它会变慢:
mysql> SELECT COUNT(a.alarm_id) AS `count`, MAX(a.alarm_id) AS `max_alarm_id`, `a`.`priority`
-> FROM `alarm` AS `a`
-> WHERE (a.maintenance_suppress = '0')
-> AND (a.deleted_at = '0000-00-00 00:00:00')
-> AND (a.object_id = '68')
-> GROUP BY `a`.`priority`;
+-------+--------------+----------+
| count | max_alarm_id | priority |
+-------+--------------+----------+
| 8 | 1278404 | 2 |
+-------+--------------+----------+
1 row in set (0.01 sec)
mysql> SELECT COUNT(a.alarm_id) AS `count`, MAX(a.alarm_id) AS `max_alarm_id`, `a`.`priority`
-> FROM `alarm` AS `a` FORCE INDEX (alarm_count_b)
-> WHERE (a.maintenance_suppress = '0')
-> AND (a.deleted_at = '0000-00-00 00:00:00')
-> AND (a.object_id = '68')
-> GROUP BY `a`.`priority`;
+-------+--------------+----------+
| count | max_alarm_id | priority |
+-------+--------------+----------+
| 8 | 1278404 | 2 |
+-------+--------------+----------+
1 row in set (0.67 sec)
有人知道我的索引有什么问题吗?
SQL fiddle 玩转: http://sqlfiddle.com/#!9/23949/1
怀疑升级可能产生影响的原因是它在升级时进行了分析 TABLE,因此现在从更新的统计信息中选择一个索引。
它现在使用的索引对于 WHERE 子句中的列似乎更合乎逻辑。索引中的所有 3 列都在 WHERE 子句中使用。 alarm_count_b 索引在索引的开头有用于 GROUP BY 的列,但这只有在记录被 WHERE 子句排除后才真正有用。
然而,尝试在 object_id 索引的末尾添加优先级作为额外列。
你还没说 5.5 和 5.7 有什么区别。无论如何,您没有最佳索引,所以我将改为回答该问题。
WHERE (a.maintenance_suppress = '0')
AND (a.deleted_at = '0000-00-00 00:00:00')
AND (a.object_id = '6')
GROUP BY `a`.`priority`
以任何顺序请求 INDEX(maintenance_suppress, deleted_at, object_id, priority)
,除了 priority
必须是 last。建议您将 priority
添加到 INDEX object_id
。
作为一般规则,从开始=
条件,然后移动到一个范围条件在WHERE
.如果WHERE
完成,那么一个范围可以是GROUP BY
或ORDER BY
的所有字段。
More discussion of index building.
另一个注意事项。假设您正在使用 InnoDB,alarm_id
将成为该索引的一部分,从而使其成为 "covering"。这提供了额外的提升。 alarm_count_b
也覆盖了,但是列没有按最佳顺序排列,因此性能不佳。
没有看到你的其他查询,我无法判断你的其余索引,只能说 14 个索引是 "a lot"。