目标:分析select * from order limit 1000000,20为啥会变慢
分析:
详解:
第一部分 limit分析
1、Server层与存储引擎层
通常来说,MySQL分为Server层与存储引擎层。
- Server层:包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务。以及所有的内置函数,所有跨存储引擎的功能(比如存储过程、触发器、视图等)。
- 存储引擎层:负责数据的存储和读取。其架构模式是插件式的,支持InnoDB、MyISAM等存储引擎。 下边我们来看这个SQL是怎么执行的
select * from order limit 1000000,20
- 连接器:服务端跟客户端建立连接
- 查询缓存:是否命中缓存,命中就直接返回。
- 分析器:词法分析,语法分析
- 优化器:选择索引,确定执行方案
- 执行器:执行sql, 执行器从存储层获取数据。
- 存储引擎层:根据需求返回数据给执行器,会多次返回。
为什么经过层层优化,执行的sql还是这么慢呢?继续分析
2、limit在哪里执行?
limit是在什么时候执行的?从上边分析可以看到,有这两个阶段可以执行
- 第一种在优化器阶段已经分析好了,在执行器阶段,直接跳过1000000行,取20条数据;(向存储层获取数据20次)
- 第二种在优化器阶段不处理,在执行器阶段拿到所有数据再做处理;limit是在返回数据给客户端的时候才执行的。(向存储层获取数据1000020次,时间花费在了io上) mysql选择的是第二种。
第二部分 limit优化
根据上边的分析,我们可以根据第一部分第2小节的第一种方法来优化SQL。
1、子查询
SELECT * FROM order WHERE id > =(select id from order limit 1000000, 1) limit 20
select id from order limit 1000000, 1这个可以直接使用主键id索引,因为只查询id,相当于使用了覆盖索引,不需要不停回表取数据;(id要有索引)- 然后还是根据主键索引过滤where条件,(where条件要有索引)
- 之后拿到20条数据。
2、join联表
SELECT * FROM order a JOIN (select id from order limit 1000000, 20) b ON a.id = b.id
原理同上