分页查询
语法
select _column,_column from _table [where Clause] [limit N][offset M]
- select * : 返回所有记录
- limit N : 返回 N 条记录
- offset M : 跳过 M 条记录, 默认 M=0, 单独使用似乎不起作用
limit N,M : 相当于 limit M offset N , 从第 N 条记录开始, 返回 M 条记录
举个栗子
- 默认取0-10;
select name,age,sex from user limit 10;
10表示显示记录的条数。如果小于查询结果的总数,则会从第一条记录开始,显示指定条数的记录。如果大于查询结果的总数,则会直接显示查询出来的所有记录。
- 取出来以后偏移一个再取3个;
select name,age,sex from user limit 1.3;
select name,age,sex from user limit 3 offset 1;
注意:LIMIT 后的两个参数必须都是正整数。
每页展示的条数
如果有pageno页,每一页想展示pagenum=20行记录;
select * from user limit (pageno-1)*pagenum,pagenum;
由于存在偏移,所以第一页和最后一页的效率不均等,所以需要过滤掉偏移的耗费,直接通过带索引的列过滤掉前面页的数据。
select * from user where id>上一页最后一条数据的id值 limit 20;
通过id(带有索引值的字段,会以常量的时间把前面的数据过滤掉)过滤,这样每一页花费的时间基本是平均的。
explain 查看SQL语句的执行计划
在 MySQL 中可以通过 explain 关键字模拟优化器执行 SQL语句,从而知道 MySQL 是如何处理 SQL 语句的。
MySQL整个查询的过程
- 客户端向 MySQL 服务器发送一条查询请求
- 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段
- 服务器进行 SQL 解析、预处理、再由优化器生成对应的执行计划
- MySQL 根据执行计划,调用存储引擎的 API 来执行查询
- 将结果返回给客户端,同时缓存查询结果
注意:只有在8.0之前才有查询缓存,8.0之后查询缓存被去掉了
启动执行计划
explain select 投影列 FROM 表名 WHERE 条件
explain只是一个大致的值,不会展示sql的优化操作,如果有join连接查询,会输出两行
每一列的含义
id
查询执行顺序:
- id 值相同时表示从上向下执行
- id 值相同被视为一组
- 如果是子查询,id 值会递增,id 值越高,优先级越高
- id为NULL最后执行。
select_type
- simple:表示查询中不包含子查询或者 union
- primary:当查询中包含任何复杂的子部分,最外层的查询被标记成 primary
- derived:在 from 的列表中包含的子查询被标记成 derived
- subquery:在 select 或 where 列表中包含了子查询,则子查询被标记成 subquery
- union:两个 select 查询时前一个标记为 PRIMARY,后一个标记为 UNION。union 出现在 from 从句子查询中,外层 select 标记为 PIRMARY,union 中第一个查询为 DERIVED,第二个子查询标记为 UNION
- union result:从 union 表获取结果的 select 被标记成 union result 。
table
显示这一行的数据是关于哪张表的。
当 from 子句中有子查询时,table列是 格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。
当有 union 时,UNION RESULT 的 table 列的值为<union1,2>,1和2表示参与 union 的 select 行id。
type
显示连接使用了何种类型。从最好到最差的连接类型为 system > const > eq_reg > ref > range > index > ALL。一般来说,得保证查询达到range级别,最好达到ref
NULL
:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表system
:表中只有一行数据,属于 const 的特例。如果物理表中就一行数据为 ALLconst
:查询结果最多有一个匹配行。因为只有一行,所以可以被视为常量。const 查询速度非常快,因为只读一次。一般情况下把主键或唯一索引作为唯一条件的查询都是 consteq_ref
:查询时查询外键表全部数据。且只能查询主键列或关联列。且外键表中外键列中数据不能有重复数据,且这些数据都必须在主键表中有对应数据(主键表中数据可以有没有用到的)ref
:比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。range
:把这个列当作条件只检索其中一个范围。常见 where 从句中出现 between、<、>、>=、in 等。主要应用在具有索引的列中index
:扫描全索引就能拿到结果,一般是扫描某个二级索引,这种扫描不会从索引树根节点开始快速查找,而是直接对二级索引的叶子节点遍历和扫描,速度还是比较慢的,这种查询一般为使用覆盖索引,二级索引一般比较小,所以这种通常比ALL快一些- ALL:即全表扫描,扫描你的聚簇索引的所有叶子节点。通常情况下这需要增加索引来进行优化了。
possible_keys
- 查询条件字段涉及到的索引,可能没有使用。
- explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。
- 如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查 where 子句看是否可以创造一个适当的索引来提高查询性能,然后用 explain 查看效果
key
- 实际使用的索引。如果为 NULL,则没有使用索引。
- 如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 forceindex、ignore index。
key_len
表示索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。key_len 是根据表定义计算而得的,不是通过表内检索出的。
ref
显示索引的哪一列被使用了,如果可能的话,是一个常量 const。
rows
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。注意这个不是结果集里的行数。
fitered
显示了通过条件过滤出的行数的百分比估计值。
Extra
MYSQL 如何解析查询的额外信息。
Distinct:MySQL
发现第 1 个匹配行后,停止为当前的行组合搜索更多的行。Not exists
:MySQL 能够对查询进行 LEFT JOIN 优化,发现 1 个匹配 LEFT JOIN 标准的行后,不再为前面的的行组合在该表内检查更多的行。range checked for each record (index map: #)
:MySQL 没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。Using filesort
:MySQL 需要额外的一次传递,以找出如何按排序顺序检索行。将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。一般要考虑使用索引来优化的。actor.name
未创建索引,会浏览actor整个表,保存排序关键字name和对应的id,然后排序name并检索行记录Using index
:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。(使用覆盖索引—mysql执行计划explain结果里的key有使用索引,如果select后面查询的字段都可以从这个索引的树中获取,这种情况一般可以说是用到了覆盖索引,extra里一般都有using index;覆盖索引一般针对的是辅助索引,整个查询结果只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其它字段值)Using temporary
:为了解决查询,MySQL 需要创建一个临时表来容纳结果。Using where
:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户,并且查询的列未被索引覆盖Using sort_union(…), Using union(…), Using intersect(…):
这些函数说明如何 为index_merge 联接类型合并索引扫描。Using index for group-by
:类似于访问表的 Using index 方式,Using index for group-by 表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。
注意:带索引的,不会因为它在第几行就查询几行,他们都是查询一次,效率是一样的
注意:不带索引的,会进行整表搜索
对于不带索引的,加入limit会加快查找效率,找到limit限制数以后,后面的就不查了,但是explain看不出来优化,可以从时间上看到快了。