MySQL 流水线顺序似乎不起作用
MySQL pipelined order by seems not working
我有table
user[id, name, status] with index[status, name, id]
SELECT *
FROM user
WHERE status = 'active'
ORDER BY name, id
LIMIT 50
我有大约 50000 个状态为 == 'active'
的用户
1.) 为什么MySQL 解释在ROWS 列中显示大约50000?为什么即使索引列等于 order by 子句,它也会跟随所有叶节点?
2.) 当我将 order by 子句更改为
ORDER BY status, name, id
解释子句的 EXTRA 列显示:
使用索引条件;在哪里使用;使用文件排序
是否有任何原因不能在此查询中使用索引顺序?
编辑1:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `status_name_id` (`status`,`name`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
查询:
SELECT *
FROM `user`
WHERE status = 'complete'
ORDER BY status, name, id
LIMIT 50
解释:
id: 1
select_type: SIMPLE
table: f_order
type: ref
possible_keys: status_name_id
key: status_name_id
key_len: 768
ref: const
rows: 50331
Extra: "Using where; Using index; Using filesort"
最奇怪的是,如果我将 SELECT 语句更改为
SELECT *, count(id)
再次使用索引,查询速度提高一倍。额外的部分只包含
Using where; Using index
Table 包含 10 万行,5 种不同的状态和 12 个不同的名字。
MySQL: 5.6.27
编辑2:
另一个例子:
这需要 400 毫秒(平均)并进行显式排序
SELECT *
FROM `user`
WHERE status IN('complete')
ORDER BY status, name, id
LIMIT 50
这需要 2 毫秒(平均)并且没有显式排序
SELECT *
FROM `user`
WHERE status IN('complete', 'something else')
ORDER BY status, name, id
LIMIT 50
Q1: EXPLAIN
有点蹩脚。在提供 Rows
估计时,它没有考虑 LIMIT
的存在。放心,如果它能做空,它就会做空。
Q2:有说用你的索引吗?请提供完整的 EXPLAIN
和 SHOW CREATE TABLE
.
更多
与INDEX(status, name, id)
、WHERE
、ORDER BY
、和LIMIT
都可以在索引中处理。因此它只需要读取 50 行。
如果没有该索引(或者对查询进行任何实际更改),大部分或全部 table 将需要读取、存储在 tmp table 中、排序,并且仅那么能不能剥掉50行呢
所以,我建议它比"explicit sort can kill my db server"更复杂。
根据评论,这可能是错误。
我有table user[id, name, status] with index[status, name, id]
SELECT *
FROM user
WHERE status = 'active'
ORDER BY name, id
LIMIT 50
我有大约 50000 个状态为 == 'active'
的用户1.) 为什么MySQL 解释在ROWS 列中显示大约50000?为什么即使索引列等于 order by 子句,它也会跟随所有叶节点?
2.) 当我将 order by 子句更改为
ORDER BY status, name, id
解释子句的 EXTRA 列显示:
使用索引条件;在哪里使用;使用文件排序
是否有任何原因不能在此查询中使用索引顺序?
编辑1:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `status_name_id` (`status`,`name`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
查询:
SELECT *
FROM `user`
WHERE status = 'complete'
ORDER BY status, name, id
LIMIT 50
解释:
id: 1
select_type: SIMPLE
table: f_order
type: ref
possible_keys: status_name_id
key: status_name_id
key_len: 768
ref: const
rows: 50331
Extra: "Using where; Using index; Using filesort"
最奇怪的是,如果我将 SELECT 语句更改为
SELECT *, count(id)
再次使用索引,查询速度提高一倍。额外的部分只包含
Using where; Using index
Table 包含 10 万行,5 种不同的状态和 12 个不同的名字。
MySQL: 5.6.27
编辑2:
另一个例子:
这需要 400 毫秒(平均)并进行显式排序
SELECT *
FROM `user`
WHERE status IN('complete')
ORDER BY status, name, id
LIMIT 50
这需要 2 毫秒(平均)并且没有显式排序
SELECT *
FROM `user`
WHERE status IN('complete', 'something else')
ORDER BY status, name, id
LIMIT 50
Q1: EXPLAIN
有点蹩脚。在提供 Rows
估计时,它没有考虑 LIMIT
的存在。放心,如果它能做空,它就会做空。
Q2:有说用你的索引吗?请提供完整的 EXPLAIN
和 SHOW CREATE TABLE
.
更多
与INDEX(status, name, id)
、WHERE
、ORDER BY
、和LIMIT
都可以在索引中处理。因此它只需要读取 50 行。
如果没有该索引(或者对查询进行任何实际更改),大部分或全部 table 将需要读取、存储在 tmp table 中、排序,并且仅那么能不能剥掉50行呢
所以,我建议它比"explicit sort can kill my db server"更复杂。
根据评论,这可能是错误。