limit入坑指南一:回表查询

limit 原理

第一步.先查询offset+count条数据;
第二步.再抛弃前offset条数据

Limit效率高:数据库的数量很大,但是只需要查询一部分数据的情况。
  高效率的原理是:避免全表扫描,提高查询效率。
在这里插入图片描述
上图员工表的查询即全表扫描,那么怎么避免全表扫描

加上LIMIT 1,只要找到了对应的一条记录,就不会继续向下扫描了,效率会大大提高。

imit的效率低:只使用limit来查询语句,并且偏移量特别大的情况
  现在有一个订单表,数据量达到千万级表(真正不会这么查询,这里只是举例)
语句1:
  select * from order limit 4,2 用时0.086s
语句2:
select * from order limit 4000000,2 用时8.379s   
为什么语句2比语句1慢了将近100倍,这个数字会随着偏移量增加而增加

mysql索引

InnoDB的聚集索引

聚集索引的叶子节点存储每条记录数据
InnoDB必须要有且只有一个聚集索引,下面聚集索引的生成规则:

如果表定义了PK(Primary Key,主键),那么PK就是聚集索引。
如果表没有定义PK,则第一个NOT NULL UNIQUE的列就是聚集索引。
否则InnoDB会另外创建一个隐藏的ROWID作为聚集索引。

这种机制使得基于PK的查询速度非常快,因为直接定位行记录。

InnoDB普通索引

InnoDB普通索引的叶子节点存储主键值。想拿到行数据,还得去聚集索引中扫描索引树。

注意,不是存储行记录头指针,MyISAM的索引叶子节点存储记录指针

回表查询

如果索引的列在 select 所需获得的列中或者根据一次索引查询就能获得记录就不需要回表如果 select 所需获得列中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表。

举个例子,员工表我要查询id为1的员工
select * from employee where id = 1
因为id是主键(聚集索引),根据主键的查询方式,则只需要搜索 ID 这棵 B+ 树。主键是唯一的,根据这个唯一的索引,MySQL 就能确定搜索的记录。

而下面的语句则需要进行徽标查询,虽然emp_no是普通索引,但是查询了除emp_no以外的字段
selelct * from employee where emp_no = ‘zs‘
原因是通过 emp_no 这个普通索引查询方式,则需要先搜索 emp_no 索引树,然后得到主键 ID 的值为 1,再到 ID 索引树搜索一次。这个过程虽然用了索引,但实际上底层进行了两次索引查询,这个过程就称为回表。

所以limit随偏移量增加而增加是因为进行了多次的回表查询

那么怎么避免回表呢?索引覆盖

如果一个索引覆盖(包含)了所有需要查询的字段的值,这个索引就是覆盖索引,因为覆盖索引必须要存储索引的列值,而哈希索引、空间索引和全文索引等都不存储索引列值,所以MySQL只能使用B-Tree索引做覆盖索引。

覆盖索引就是把所有需要查询的字段都放到普通索引中,这样普通索引查到的叶子结点中已经能够得到所需的所有字段,就不会再去聚集索引中再查询。即sql改为
selelct emp_no from employee where emp_no = ‘zs‘

覆盖索引不仅可以通过减少查询字段只查询索引有的字段来实现,还可以通过联合索引来将多个字段设置为一个索引来实现

偏移量大的sql怎么优化呢

有的时候索引覆盖也不能解决上述问题,那么我们就应该优化语句做到避免回表查询

1 采用where…limit…

where id > offset limit count
巧妙利用聚集索引定位记录行避开回表
但不是所有的表主键都是id,也不是所有的id都是连续的

2.延迟关联或者子查询
select emp.* from employee emp
inner join(select id from employee limit 4000000)tmp
on emp.id = tmp.id
用时 0.860S 速度提升10倍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值