尽管查询很简单,但下面的执行计划似乎令人失望和次优。
我正在使用 MySQL 5.7。这是小提琴(虽然它只提供 5.6)。
CREATE TABLE `event` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(63) CHARSET ASCII COLLATE ASCII_BIN NOT NULL,
`is_sequenced` TINYINT(3) UNSIGNED NOT NULL,
`sequence_number` BIGINT(20) UNSIGNED DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Name-SequenceNumber` (`name`,`sequence_number`),
KEY `Name-IsSequenced` (`name`,`is_sequenced`,`id`)
) ENGINE=INNODB
;
INSERT INTO `event`
(id, `name`, is_sequenced, sequence_number)
VALUES
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL),
(NULL, 'OrderCreated', 0, NULL)
;
我们将使用Name-IsSequenced
二级索引。让我们尝试以下EXPLAIN
. (查询在小提琴中。打开“查看执行计划”以查看其EXPLAIN
结果。)
EXPLAIN
SELECT * -- This part needs the PK
FROM `event` e
WHERE e.name = 'OrderCreated'
AND e.is_sequenced = 0
AND e.id <= 3
;
到目前为止,一切都很好。Using index condition
有道理:整个条件可以在预期的索引上解决Name-IsSequenced
,然后需要PK来获取剩余的数据SELECT *
。
Using index
如果我们只选择二级索引的一部分,我们应该能够改进它,对吧?(请注意,PK 始终是任何二级索引的一部分,但我们甚至可以通过id
在二级索引的末尾添加来确保这一点。结果应该是一样的。)
EXPLAIN
SELECT id
FROM `event` e
WHERE e.name = 'OrderCreated'
AND e.is_sequenced = 0
AND e.id <= 3
;
现在,结果是Using where; Using index
。等等,这……更糟?!我们减少了它的工作量,而计划表明它正在更加努力地工作。
Using index
应该是可以实现的。找到范围 where name=OrderCreated
,然后在其中找到子范围 where is_sequenced=0
,然后在里面找到子范围 where id<=3
。
奇怪的是,我还有其他实验(有更多数据),我可以Using index
通过更改id<=3
来获得id=3
(结合FORCE INDEX
以防止它更喜欢 PK)。我看不出差异的原因。(如果我们用 Fiddle 试试这个,它保持不变 - 可能是因为数据集小。)
谁能解释为什么执行计划没有表明二级索引的预期有效使用?有没有办法把它弄直?