MySQL 没有使用带 ORDER BY 子句的复合索引
MySQL is not using composite index with ORDER BY clause
我有一个 table user
看起来像这样
id | first_name | last_name | org_id
这个table有几百万条目。
我想 运行 下面的查询具有完全匹配和 order by 子句
select * from user
where org_id = "some id"
ORDER BY first_name asc, last_name asc
limit 100;
我还有以下指标:
- org_id
- org_id、first_name、last_name
当我 运行 对此查询进行解释时,mysql 使用 org_id
索引而不是 org_id, first_name, last_name
上的复合索引。
这是解释查询的输出
我可以在 possible keys
部分中看到 mysql 评估了复合索引但仍未使用它。
我已经阅读了几个答案,例如 this 其中一个说应该在此处使用复合索引。
万一真的匹配,这个查询真的很慢。任何想法
- 为什么mysql没有使用复合索引?
- 我怎样才能加快这个查询?
编辑 1:这是 table DDL
CREATE TABLE `user` (
`organisation_id` bigint(20) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`id` bigint(20) NOT NULL,
`first_name` varchar(255) DEFAULT NULL,
`middle_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `organisation_id` (`organisation_id`,`email`),
KEY `idx_first_name_last_name` (`first_name`(32),`last_name`(32)),
KEY `idx_organisation_id_first_name_last_name` (`organisation_id`,`first_name`(32),`last_name`(32)),
CONSTRAINT `user_org_fkey` FOREIGN KEY (`organisation_id`) REFERENCES `organisation` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
TIA
更新:Liki 提到的更新索引解决了我的问题
我认为优化器会 select 复合索引,如您所料。 (但它不在你的数据库中)
我在我的测试数据库上测试了相同的情况,但它 select 是复合索引。
幸运的是,MySQL 中有一个用于优化器决策的索引提示。
tbl_name [[AS] alias] [index_hint_list]
index_hint_list:
index_hint [index_hint] ...
index_hint:
USE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
| {IGNORE|FORCE} {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
index_list:
index_name [, index_name] ...
示例:
SELECT * FROM table1 USE INDEX (col1_index,col2_index)
WHERE col1=1 AND col2=2 AND col3=3;
SELECT * FROM table1 IGNORE INDEX (col3_index)
WHERE col1=1 AND col2=2 AND col3=3;
最后,您可以尝试 运行 您的 SQL 并使用以下提示吗?
select
*
from
`user` USE INDEX (your_composit_index_name)
where org_id = "some id"
ORDER BY first_name asc,
last_name asc
limit 100;
编辑 1:索引修正
请修复您的索引。您的密钥 lengths
在索引 idx_first_name_last_name
中定义为 32,但它们的长度应为 255。
ALTER TABLE `user` DROP INDEX `idx_first_name_last_name`, ADD KEY `idx_first_name_last_name` (`first_name`, `last_name`);
DROP
你的 INDEX(org_id)
,它可能会妨碍使用更好的 INDEX(org_id, first, last)
。如果这有帮助,它将添加更多证据证明这个严重的优化缺陷。
我有一个 table user
看起来像这样
id | first_name | last_name | org_id
这个table有几百万条目。
我想 运行 下面的查询具有完全匹配和 order by 子句
select * from user
where org_id = "some id"
ORDER BY first_name asc, last_name asc
limit 100;
我还有以下指标:
- org_id
- org_id、first_name、last_name
当我 运行 对此查询进行解释时,mysql 使用 org_id
索引而不是 org_id, first_name, last_name
上的复合索引。
这是解释查询的输出
我可以在 possible keys
部分中看到 mysql 评估了复合索引但仍未使用它。
我已经阅读了几个答案,例如 this 其中一个说应该在此处使用复合索引。
万一真的匹配,这个查询真的很慢。任何想法
- 为什么mysql没有使用复合索引?
- 我怎样才能加快这个查询?
编辑 1:这是 table DDL
CREATE TABLE `user` (
`organisation_id` bigint(20) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`id` bigint(20) NOT NULL,
`first_name` varchar(255) DEFAULT NULL,
`middle_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `organisation_id` (`organisation_id`,`email`),
KEY `idx_first_name_last_name` (`first_name`(32),`last_name`(32)),
KEY `idx_organisation_id_first_name_last_name` (`organisation_id`,`first_name`(32),`last_name`(32)),
CONSTRAINT `user_org_fkey` FOREIGN KEY (`organisation_id`) REFERENCES `organisation` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
TIA
更新:Liki 提到的更新索引解决了我的问题
我认为优化器会 select 复合索引,如您所料。 (但它不在你的数据库中)
我在我的测试数据库上测试了相同的情况,但它 select 是复合索引。
幸运的是,MySQL 中有一个用于优化器决策的索引提示。
tbl_name [[AS] alias] [index_hint_list]
index_hint_list:
index_hint [index_hint] ...
index_hint:
USE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
| {IGNORE|FORCE} {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
index_list:
index_name [, index_name] ...
示例:
SELECT * FROM table1 USE INDEX (col1_index,col2_index)
WHERE col1=1 AND col2=2 AND col3=3;
SELECT * FROM table1 IGNORE INDEX (col3_index)
WHERE col1=1 AND col2=2 AND col3=3;
最后,您可以尝试 运行 您的 SQL 并使用以下提示吗?
select
*
from
`user` USE INDEX (your_composit_index_name)
where org_id = "some id"
ORDER BY first_name asc,
last_name asc
limit 100;
编辑 1:索引修正
请修复您的索引。您的密钥 lengths
在索引 idx_first_name_last_name
中定义为 32,但它们的长度应为 255。
ALTER TABLE `user` DROP INDEX `idx_first_name_last_name`, ADD KEY `idx_first_name_last_name` (`first_name`, `last_name`);
DROP
你的 INDEX(org_id)
,它可能会妨碍使用更好的 INDEX(org_id, first, last)
。如果这有帮助,它将添加更多证据证明这个严重的优化缺陷。