本文首发于我的微信公众号《andqian》,期待你的关注!mysql
前面写了《读懂MySQL执行计划》和《写会MySQL索引》后,今天咱们来讲说MySQL中另一个比较重要的概念,就是 LIMIT 关键字。面试
LIMIT的概念,其实你们应该都很清楚,在百度百科中是这样描述的:sql
LIMIT是一种数据语言,主要是用于查询以后要显示返回的前几条或者中间某几行数据。微信
这里着重须要注意的是: offset为开始角标,count表明数量,以下图所示:数据结构
(图片来源: mysqltutorial)优化
理解了这个概念以后,咱们就可以知道下面这两个语句的意思了:spa
LIMIT 0,100; (A)
LIMIT 10,100; (B)索引
语句A表明的是 : 从起始角标为0的位置,日后获取100条记录。图片
语句B表明的是 : 从起始角标为10的位置,日后获取100条记录。开发
(别觉得这很简单,在以前的面试过程当中,就有不少童鞋搞混了,将语句B理解成了: 从起始角标为10的位置,获取90条数据呢。)
其实,LIMIT还有一个比较经常使用的简化写法,以下所示:
LIMIT 100;
这其实就是对上述A语句的简化,其意思表明的是: 从其实角标为0的位置,日后获取100条记录。只是将其实角标0省略掉了而已。正是由于这样的特性,有不少应用也直接使用LIMIT来进行分页操做。
上面咱们介绍了,LIMIT的概念,也理清楚了LIMIT每一个参数的含义,那如今就留一个问题:
问: LIMIT 0,100与 LIMIT 100000,100的执行效率是同样吗? 同样为何?不同又为何?
ps: 在Java面试时会常常问到哦。我以前就被问到过。
咱们都知道, LIMIT通常是跟在order by xx asc|desc语句后的,接下来咱们就来看看下面这两个语句,一块儿来分析一下上述问题的答案:
语句A:
select * from t_base_user order by oid desc limit 0,100;
语句B:
select * from t_base_user order by oid desc limit 10000,100;
分别看下执行计划:
语句A的执行计划是:
explain select * from t_base_user order by oid desc limit 0,100;
结果:
语句B的执行计划是:
explain select * from t_base_user order by oid desc limit 10000,100;
结果:
到这里,咱们会发现扫描的行数是彻底不同的,在语句B中,其实MySQL实际扫描1000100行记录,而后只返回100条记录,将前面的1000000条记录活生生的抛弃掉,你说这成本大不大,代价高不高? 看到这里,咱们应该已经知道上面问题的答案了。
如今咱们来讲说如何优化LIMIT,咱们知道,在offset比较大的时候,效率会很是低,因此,对LIMIT优化,要么限制分页的数量,要么下降offset的大小。 例如:
select * from t_base_user limit 100000,100
好比上面这语句,由于咱们主键是连续的。
方法一 : 咱们就能够经过这样来优化:
select * from t_base_user where oid between 100000 and 1000100;
此时若是咱们看执行计划的话,其实type已经从all(全表扫描)扫描优化到range(范围查找),也走了PRIMARY索引。
方法二: 咱们能够倒序LIMIT 若是咱们表中一共有120万数据,此时咱们就能够倒序LIMIT,以下所述:
select * from t_base_user order by oid desc limit 100;
或者这样:
select * from t_base_user where oid<1000000 order by oid desc limit 100;
一样也达到来优化的效果。
本文全部数据,均基于如下数据结构:
create table t_base_user(
oid bigint(20) not null primary key auto_increment,
name varchar(30) null comment "name",
email varchar(30) null comment "email",
age int null comment "age",
telephone varchar(30) null comment "telephone",
status tinyint(4) null comment "0 无效 1 有效",
created_at datetime null default now() comment "建立时间",
updated_at datetime null default now() comment "修改时间"
)
// 新增记录: insert into t_base_user(name,email,age,telephone,status,created_at,updated_at) values ("andyqian","andytohome",20,"15608411",1,now(),now());
这里提供一个简单的方法复制数据
insert into t_base_user(name,email,age,telephone,status) select name,email,age,telephone,status from t_base_user;
使用该语句,能够快速的复制数据。执行屡次后,就可以生成很多数据,(备注: 该数据仅用做LIMIT关键字演示,新建索引,计算区分度其值误差会比较大,请勿将该结果做为建索引的参考值。)
上面对MySQL LIMIT关键字作了详细的讲解,你可别小瞧它哦,它在平时开发中有很大的用处哦,例如: 在平时开发查询数据时,加上LIMIT后,查询效果可会大大增长,能节省很多时间呢。在查询数据时养成加上LIMIT是一个不错的习惯。
最后: 祝你们晚安!
相关阅读:
扫码关注,一块儿进步
我的博客: http://www.andyqian.com