MySQL показывает индекс в плане выполнения, но не использует его - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть таблица с 20M строками и запросом, который занимает 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

Но если я даю подсказку для использования индекса, который был в 'объяснение расширенного' , тополное сканирование и запрос не выполняются за 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

Сканировано только 166 КБ объектов

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

«объяснить расширенный» показывает один и тот же план выполнения в каждомcase «анализ» не помогает.

таблица «сущность»:

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 |
+--------------------+

1 Ответ

0 голосов
/ 26 ноября 2018

Хорошо, я частично нашел ответ: MySQL Workbench, который я использую, неявным образом добавляет «лимит 1000» к запросам, и это резко снижает производительность, даже если в ответе гораздо меньше строк.С лимитом объяснение расширенный показывает ПЕРВИЧНЫЙ как ключ, и это больше не вопрос.Если я увеличу лимит до 10000, запрос завершится через 250 мс.Похоже, в оптимизаторе MySQL есть некоторая эвристика, которая заставляет его использовать индекс PRIMARY в случае низкого «лимита».

...