limit
现有表a,分页查找数据,SQL语句如下:
select * from a where phone='123' order by id desc limit 90000,5
底层查询到90005,然后丢掉90000条,可想而知随着数值越大,执行效率越来越低,导致磁盘IO消耗过大。
优化方案1,SQL如下
select id from a where phone='123' order by id desc limit 90000,5
通过使用覆盖索引,一次IO可以读取大量数据,降低磁盘IO次数。
优化方案2,SQL如下
select * from a id>= (select id from a where phone='123' order by id desc limit 90000,1) limit 5
select * from a join (select id from a where phone='123' order by id desc limit 90000,20) b ON a.id= b.id
采用覆盖索引,快速定位到id,然后回表查询该列所有数据。
连接查询
Nested-Loop join(嵌套循环连接),驱动表a,被驱动表b,原理如下
- 读取1行a表数据;
- 在a获取关联字段在b表查询;
- 取出b表满足条件的行,跟a表获得结果合并。
- 重复上诉1,2,3;
Block Nested-Loop join(块嵌套循环连接),驱动表a,被驱动表b,原理如下
- 读取a表数据到内存;
- 遍历b表一行数据,在内存与a数据对比;
- 重复步骤2。
NLJ适合有索引,BNLJ适合无索引。
in与exists
- 在mysql8.0以前(5.7),使用exists(不走索引)效率低下,使用in效率高。
- mysql 8.0 对 exists做出优化,效率跟in相当。
在mysql8.0.18版本新增的 explain format=tree 查看执行计划的方法。
EXPLAIN SELECT * FROM card WHERE not EXISTS (SELECT phone FROM `user` WHERE card.phone =`user`.phone)
EXPLAIN format=tree SELECT * FROM card WHERE not EXISTS (SELECT phone FROM `user` WHERE card.phone =`user`.phone)
被优化成了半连接,文献。
not in 在explain 分析结果:
EXPLAIN SELECT * FROM card WHERE phone not in (SELECT phone FROM `user` WHERE card.phone =`user`.phone)
DEPENDENT SUBQUERY:依赖只查询,获取user表数据时候会依赖外表card数据,我现在user表找数据然后再去card表找匹配合适结果。效率相当低下,可以优化SQL成连接查询。参考