MySQL 显示执行计划中的索引,但并未真正使用它
MySQL shows index in execution plan, but doesn't really use it
我有一个包含 2000 万行的 table 和一个需要 10 秒的查询。
select id from entity
where (entity.class_id = 67 and entity.name like '%321%' )
order by id desc
在执行计划中有一个索引,但它并没有真正被使用。
explain extended select id from entity
where (entity.class_id = 67 and entity.name like '%321%' )
order by id desc
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
| 1 | SIMPLE | entity | ref | constraint_unique_class_legacy_id,entity_tag,entity_class_modification_date_int_idx,entity_name_idx | entity_class_modification_date_int_idx | 8 | const | 288440 | 100.00 | Using where; Using filesort |
如果我刷新状态和 运行 这个查询,处理程序显示有一个完整的扫描
Handler_read_next: 20318800
但是如果我给出 提示使用 'explain extended' 中的索引,则没有完整扫描,查询在 250 毫秒内完成。
select id from entity
use index (entity_class_modification_date_int_idx)
where (entity.class_id = 67 and entity.name like '%321%' )
order by id desc
只扫描了 166K 个实体
Handler_read_next: 165894
为什么我必须提示使用已经在执行计划中的索引?
如果我将 + 0 添加到排序依据,查询也会在 250 毫秒内完成。
select id from entity
where (entity.class_id = 67 and entity.name like '%321%' )
order by id + 0 desc
'explain extended' 在每种情况下都显示相同的执行计划,'analyze' 没有帮助。
Table 'entity':
CREATE TABLE `entity` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(4096) COLLATE utf8_bin DEFAULT NULL,
`tag` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`revision` int(11) NOT NULL,
`class_id` bigint(20) NOT NULL,
`legacy_id` bigint(20) DEFAULT NULL,
`description` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`last_modified_by` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`removed` tinyint(1) NOT NULL DEFAULT '0',
`modification_date_int` bigint(20) DEFAULT NULL,
`creation_date_int` bigint(20) DEFAULT NULL,
`created_by` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`ancestor_class_id` bigint(20) NOT NULL,
`acu_id` bigint(20) DEFAULT NULL,
`secured` tinyint(1) DEFAULT '1',
`system_modification_date` bigint(20) DEFAULT NULL,
`archived` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `constraint_unique_class_legacy_id` (`class_id`,`legacy_id`),
UNIQUE KEY `entity_tag` (`class_id`,`tag`),
UNIQUE KEY `class_hierarchy_tag` (`tag`,`ancestor_class_id`),
KEY `entity_legacy_id_idx` (`legacy_id`),
KEY `entity_modification_date_int_idx` (`modification_date_int`),
KEY `entity_class_modification_date_int_idx` (`class_id`,`removed`,`modification_date_int`),
KEY `ancestor_class_id` (`ancestor_class_id`),
KEY `acu_id` (`acu_id`),
KEY `entity_name_idx` (`class_id`,`name`(255)),
KEY `entity_archived_idx` (`archived`),
CONSTRAINT `entity_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`),
CONSTRAINT `entity_ibfk_2` FOREIGN KEY (`ancestor_class_id`) REFERENCES `class` (`id`),
CONSTRAINT `entity_ibfk_3` FOREIGN KEY (`acu_id`) REFERENCES `acu` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=60382455 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
MySQL版本:
SELECT @@version;
+--------------------+
| @@version |
+--------------------+
| 5.6.30-76.3-56-log |
+--------------------+
好的,我找到了部分答案:我正在使用的 MySQL Workbench 是隐式添加 'limit 1000' 到查询中,即使行数少得多,它也会大大降低性能作为回应。限制 'explain extended' 将 PRIMARY 显示为键,这不再是问题。如果我将限制增加到 10000,则查询将在 250 毫秒内完成。看起来 MySQL 优化器中有一些启发式方法,它强制它在低 'limit'.
的情况下使用 PRIMARY 索引
我有一个包含 2000 万行的 table 和一个需要 10 秒的查询。
select id from entity
where (entity.class_id = 67 and entity.name like '%321%' )
order by id desc
在执行计划中有一个索引,但它并没有真正被使用。
explain extended select id from entity
where (entity.class_id = 67 and entity.name like '%321%' )
order by id desc
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
| 1 | SIMPLE | entity | ref | constraint_unique_class_legacy_id,entity_tag,entity_class_modification_date_int_idx,entity_name_idx | entity_class_modification_date_int_idx | 8 | const | 288440 | 100.00 | Using where; Using filesort |
如果我刷新状态和 运行 这个查询,处理程序显示有一个完整的扫描
Handler_read_next: 20318800
但是如果我给出 提示使用 'explain extended' 中的索引,则没有完整扫描,查询在 250 毫秒内完成。
select id from entity
use index (entity_class_modification_date_int_idx)
where (entity.class_id = 67 and entity.name like '%321%' )
order by id desc
只扫描了 166K 个实体
Handler_read_next: 165894
为什么我必须提示使用已经在执行计划中的索引?
如果我将 + 0 添加到排序依据,查询也会在 250 毫秒内完成。
select id from entity
where (entity.class_id = 67 and entity.name like '%321%' )
order by id + 0 desc
'explain extended' 在每种情况下都显示相同的执行计划,'analyze' 没有帮助。
Table 'entity':
CREATE TABLE `entity` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(4096) COLLATE utf8_bin DEFAULT NULL,
`tag` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`revision` int(11) NOT NULL,
`class_id` bigint(20) NOT NULL,
`legacy_id` bigint(20) DEFAULT NULL,
`description` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`last_modified_by` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`removed` tinyint(1) NOT NULL DEFAULT '0',
`modification_date_int` bigint(20) DEFAULT NULL,
`creation_date_int` bigint(20) DEFAULT NULL,
`created_by` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`ancestor_class_id` bigint(20) NOT NULL,
`acu_id` bigint(20) DEFAULT NULL,
`secured` tinyint(1) DEFAULT '1',
`system_modification_date` bigint(20) DEFAULT NULL,
`archived` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `constraint_unique_class_legacy_id` (`class_id`,`legacy_id`),
UNIQUE KEY `entity_tag` (`class_id`,`tag`),
UNIQUE KEY `class_hierarchy_tag` (`tag`,`ancestor_class_id`),
KEY `entity_legacy_id_idx` (`legacy_id`),
KEY `entity_modification_date_int_idx` (`modification_date_int`),
KEY `entity_class_modification_date_int_idx` (`class_id`,`removed`,`modification_date_int`),
KEY `ancestor_class_id` (`ancestor_class_id`),
KEY `acu_id` (`acu_id`),
KEY `entity_name_idx` (`class_id`,`name`(255)),
KEY `entity_archived_idx` (`archived`),
CONSTRAINT `entity_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`),
CONSTRAINT `entity_ibfk_2` FOREIGN KEY (`ancestor_class_id`) REFERENCES `class` (`id`),
CONSTRAINT `entity_ibfk_3` FOREIGN KEY (`acu_id`) REFERENCES `acu` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=60382455 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
MySQL版本:
SELECT @@version;
+--------------------+
| @@version |
+--------------------+
| 5.6.30-76.3-56-log |
+--------------------+
好的,我找到了部分答案:我正在使用的 MySQL Workbench 是隐式添加 'limit 1000' 到查询中,即使行数少得多,它也会大大降低性能作为回应。限制 'explain extended' 将 PRIMARY 显示为键,这不再是问题。如果我将限制增加到 10000,则查询将在 250 毫秒内完成。看起来 MySQL 优化器中有一些启发式方法,它强制它在低 'limit'.
的情况下使用 PRIMARY 索引