为什么不同的主键查询在innodb中有巨大的速度差异?
Why different primary key queries have huge speed difference in innodb?
我有一个简单的 table Test
:
id
,主键;
id2
,索引;
- 等50+各类栏目;
而且我知道如果我 select id from Test
,它将使用二级索引 id2
而不是 this post.
中所述的主索引(聚集索引)
如果我强制使用主索引进行查询,为什么选择不同的列时结果时间相差很大?
查询 1
select id, url from Test order by id limit 1000000, 1
,仅使用 500ms+,这里是解释:
MySQL [x]> explain select id, url from Test order by id limit 1000000, 1;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| 1 | SIMPLE | Test | NULL | index | NULL | PRIMARY | 8 | NULL | 1000001 | 100.00 | NULL |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)
查询 2
select * from Test order by id limit 1000000, 1
只用了2000ms+,下面是解释:
MySQL [x]> explain select * from Test order by ID limit 1000000, 1;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| 1 | SIMPLE | Test | NULL | index | NULL | PRIMARY | 8 | NULL | 1000001 | 100.00 | NULL |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)
我看不出这两种解释有什么区别。那么为什么在结果时间上会有如此巨大的差异,因为它们使用相同的聚集索引?
- 查看sql个人资料,确定更多信息
mysql> 显示个人资料
2.mysql说明还不是很强大
3.What那种场景需要限制10000?
对于以下查询:
select id, url from t order by id limit 1000000, 1
MySQL 似乎 读取 1,000,000 行按 ID 排序而不是 跳过 它们。
我建议将查询更改为:
select * from t where id = (select id from t order by id limit 1000000, 1)
MySQL 似乎在将限制置于子查询内时跳过 1,000,000 行方面做得更好。
好吧,终于找到原因了……是因为mysqllimit的执行。 (不好意思我才找到这个中文解释,没有英文版)
在上面的查询 1 和查询 2 中,limit
执行以下操作:
- Mysql查询聚集索引,获取第一行;
- Mysql 会将第一行转换为结果;
- 然后在发送给客户端之前,Mysql发现有1000000的限制,所以第一行不是正确答案...
- Mysql 然后转到第 2 行并将其转换为结果;
- 然后在发送给客户端之前,Mysql发现有1000000的限制,所以第二行不是正确答案...;
- 周而复始,直到找到第1000001行,转换为结果后匹配
limit 1000000, 1
类;
- 所以最后,这是正确的答案,并发送给客户;
但是,它总共转换了1000000行。所以在上面的问题中,是'all fields conversion(select *
) multiply 1000000 rows'与'one/two field conversion(select id/url
) multiply 1000000 rows'之间的成本。毫无疑问,前者远比后者慢
不知道为什么 mysql limit
表现得如此笨拙,但它就是...
我有一个简单的 table Test
:
id
,主键;id2
,索引;- 等50+各类栏目;
而且我知道如果我 select id from Test
,它将使用二级索引 id2
而不是 this post.
如果我强制使用主索引进行查询,为什么选择不同的列时结果时间相差很大?
查询 1
select id, url from Test order by id limit 1000000, 1
,仅使用 500ms+,这里是解释:
MySQL [x]> explain select id, url from Test order by id limit 1000000, 1;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| 1 | SIMPLE | Test | NULL | index | NULL | PRIMARY | 8 | NULL | 1000001 | 100.00 | NULL |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)
查询 2
select * from Test order by id limit 1000000, 1
只用了2000ms+,下面是解释:
MySQL [x]> explain select * from Test order by ID limit 1000000, 1;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
| 1 | SIMPLE | Test | NULL | index | NULL | PRIMARY | 8 | NULL | 1000001 | 100.00 | NULL |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)
我看不出这两种解释有什么区别。那么为什么在结果时间上会有如此巨大的差异,因为它们使用相同的聚集索引?
- 查看sql个人资料,确定更多信息
mysql> 显示个人资料
2.mysql说明还不是很强大
3.What那种场景需要限制10000?
对于以下查询:
select id, url from t order by id limit 1000000, 1
MySQL 似乎 读取 1,000,000 行按 ID 排序而不是 跳过 它们。
我建议将查询更改为:
select * from t where id = (select id from t order by id limit 1000000, 1)
MySQL 似乎在将限制置于子查询内时跳过 1,000,000 行方面做得更好。
好吧,终于找到原因了……是因为mysqllimit的执行。 (不好意思我才找到这个中文解释,没有英文版)
在上面的查询 1 和查询 2 中,limit
执行以下操作:
- Mysql查询聚集索引,获取第一行;
- Mysql 会将第一行转换为结果;
- 然后在发送给客户端之前,Mysql发现有1000000的限制,所以第一行不是正确答案...
- Mysql 然后转到第 2 行并将其转换为结果;
- 然后在发送给客户端之前,Mysql发现有1000000的限制,所以第二行不是正确答案...;
- 周而复始,直到找到第1000001行,转换为结果后匹配
limit 1000000, 1
类; - 所以最后,这是正确的答案,并发送给客户;
但是,它总共转换了1000000行。所以在上面的问题中,是'all fields conversion(select *
) multiply 1000000 rows'与'one/two field conversion(select id/url
) multiply 1000000 rows'之间的成本。毫无疑问,前者远比后者慢
不知道为什么 mysql limit
表现得如此笨拙,但它就是...