MySQL实验 子查询优化双参数limit

没想到双参数limit还有优化的余地,为了亲眼见到,今天来亲自实验一下。

 

实验准备

使用MySQL官方的大数据库employees进行实验,导入该示例库见此

准备使用其中的employees表,先查看一下表结构和表内的记录数量

mysql> desc employees;
+------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| emp_no | int(11) | NO | PRI | NULL | |
| birth_date | date | NO | | NULL | |
| first_name | varchar(14) | NO | | NULL | |
| last_name | varchar(16) | NO | | NULL | |
| gender | enum('M','F') | NO | | NULL | |
| hire_date | date | NO | | NULL | |
+------------+---------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
mysql> select count(*) from employeed;
ERROR 1146 (42S02): Table 'employees.employeed' doesn't exist
mysql> select count(*) from employees;
+----------+
| count(*) |
+----------+
| 300024 |
+----------+
1 row in set (0.05 sec)

我们可以看到,只有主键emp_no有索引

 

实验过程

MySQL5.7官网对Explain各项参数的解释

explain参数5.7版本推荐参考博客

老版本explain推荐参考博客(即新版本默认explain extended)

关于explain参数的拓展链接

MySQL explain key值的解释

 

使用未优化双参数limit

运行一般情况下的双参数limit并explain:

mysql> select * from employees limit 200000,10;
+--------+------------+------------+------------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+------------+------------+--------+------------+
| 299976 | 1952-12-08 | Kristian | Kampfer | M | 1994-12-28 |
| 299977 | 1956-09-30 | Zsolt | Benveniste | M | 1994-08-15 |
| 299978 | 1956-08-08 | Anneli | Kitai | F | 1994-08-09 |
| 299979 | 1953-03-18 | Satoru | Kornyak | F | 1991-06-16 |
| 299980 | 1953-05-26 | Marsal | Lovengreen | M | 1988-05-09 |
| 299981 | 1960-06-22 | Claudi | Mamelak | M | 1986-07-13 |
| 299982 | 1955-06-21 | Juichirou | Hiraishi | M | 1989-12-17 |
| 299983 | 1964-11-19 | Bezalel | Iacovou | M | 1998-02-22 |
| 299984 | 1961-11-03 | Frazer | Birch | M | 1986-12-31 |
| 299985 | 1961-01-04 | Miomir | Nergos | F | 1996-07-07 |
+--------+------------+------------+------------+--------+------------+
10 rows in set (0.06 sec)
mysql> explain select * from employees limit 200000,10;
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
| 1 | SIMPLE | employees | NULL | ALL | NULL | NULL | NULL | NULL | 299468 | 100.00 | NULL |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
1 row in set, 1 warning (0.00 sec)

我们对explain进行分析:

  • type为ALL,全表扫描,也就是说没有用索引,因此key和key_len都为NULL

  • 表之间没有引用因此ref为NULL,这里是单表查询

  • partition为null说明没有使用/访问分区表

  • 扫描了299468行(limit不会过滤null和空值,为什么是这个数据还望看官解答)

  • 这里的filtered指,从存储引擎经过server层过滤后剩下有N%的数据满足查询条件,100%表示未对行进行筛选 。

  • EXTRA额外解释:Using filesort,排序时无法使用到索引时

说明双参数limit就是在排序后一直扫描到偏移量的所指的地方(这里是第100001行),然后读取10行再扔掉前100000行。

 

子查询优化limit

优化思路:先在子查询中利用“覆盖索引”的方式先找出要选取的第一行数据的主键值,然后再从这里根据主键值选取10条数据

mysql> select * from employees where emp_no >= (select emp_no from employees limit 200000,1) limit 10;
+--------+------------+------------+------------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+------------+------------+--------+------------+
| 299976 | 1952-12-08 | Kristian | Kampfer | M | 1994-12-28 |
| 299977 | 1956-09-30 | Zsolt | Benveniste | M | 1994-08-15 |
| 299978 | 1956-08-08 | Anneli | Kitai | F | 1994-08-09 |
| 299979 | 1953-03-18 | Satoru | Kornyak | F | 1991-06-16 |
| 299980 | 1953-05-26 | Marsal | Lovengreen | M | 1988-05-09 |
| 299981 | 1960-06-22 | Claudi | Mamelak | M | 1986-07-13 |
| 299982 | 1955-06-21 | Juichirou | Hiraishi | M | 1989-12-17 |
| 299983 | 1964-11-19 | Bezalel | Iacovou | M | 1998-02-22 |
| 299984 | 1961-11-03 | Frazer | Birch | M | 1986-12-31 |
| 299985 | 1961-01-04 | Miomir | Nergos | F | 1996-07-07 |
+--------+------------+------------+------------+--------+------------+
10 rows in set (0.03 sec)

可以看到,查询速度提高了一倍

mysql> explain select * from employees where emp_no >= (select emp_no from employees limit 200000,1) limit 10;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
| 1 | PRIMARY | employees | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 149734 | 100.00 | Using where |
| 2 | SUBQUERY | employees | NULL | index | NULL | PRIMARY | 4 | NULL | 299468 | 100.00 | Using index |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
2 rows in set, 1 warning (0.03 sec)

分析explain:

  • 第二行subquery指的是子查询,那么我们先从子查询看起

    type为index,说明我们使用了索引树加速查询

    key为primary key,说明我们使用了主键索引,子查询直接在主键索引树上进行了查询,避免了回表,减少了磁盘I/O

  • 第一行则是外部的查询

    type为range说明是范围查询,然后也使用了主键索引树

    而Using index是指,仅使用索引树中的信息从表中检索列信息,而无需执行其他查找即可读取实际行。

 

小结

对于不需要order by的直接的双参数limit,我们可以借助覆盖索引的方式优化查询效率。

优化order by+limit见此处

 

最后的补充

仅对于双参数limit的优化,除了子查询外还有以下方法:

  • 倒排表优化法

    倒排表法类似建立索引,用一张表来维护页数,然后通过高效的连接得到数据。缺点:只适合数据数固定的情况,数据不能删除,维护页表困难

  • 反向查找优化法

    当偏移超过一半记录数的时候,先用排序,这样偏移就反转了

    缺点:order by优化比较麻烦,要增加索引,索引影响数据的修改效率,并且要知道总记录数

    偏移大于数据的一半

    limit偏移算法:

    正向查找: (当前页 – 1) * 页长度

    反向查找: 总记录 – 当前页 * 页长度

有时间在进行实验

 

MySQL实验 子查询优化双参数limit的更多相关文章

  1. Mysql in子查询中加limit报错

    Mysql in子查询中加limit报错 select id from aa where id in ( select id from bb limit 10 ); 改写成 SELECT id FRO ...

  2. MySQL实验 内连接优化order by+limit 以及添加索引再次改进

    MySQL实验 内连接优化order by+limit 以及添加索引再次改进 在进行子查询优化双参数limit时我萌生了测试更加符合实际生产需要的ORDER BY + LIMIT的想法,或许我们也可以 ...

  3. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

  4. Mysql单表访问方法,索引合并,多表连接原理,基于规则的优化,子查询优化

    参考书籍<mysql是怎样运行的> 非常推荐这本书,通俗易懂,但是没有讲mysql主从等内容 书中还讲解了本文没有提到的子查询优化内容, 本文只总结了常见的子查询是如何优化的 系列文章目录 ...

  5. 【MySQL】MySQL中针对大数据量常用技术_创建索引+缓存配置+分库分表+子查询优化(转载)

    原文地址:http://blog.csdn.net/zwan0518/article/details/11972853 目录(?)[-] 一查询优化 1创建索引 2缓存的配置 3slow_query_ ...

  6. mysql数据库sql优化——子查询优化

    1.什么是子查询.表关联查询: 子查询:是指在主sql语句中的select或where子句中使用select查询语句:select a.name,(select b.name from b where ...

  7. 浅谈MySQL中的查询优化

    mysql的性能优化包罗甚广: 索引优化,查询优化,查询缓存,服务器设置优化,操作系统和硬件优化,应用层面优化(web服务器,缓存)等等.这里的记录的优化技巧更适用于开发人员,都是从网络上收集和自己整 ...

  8. 聊聊MySQL的子查询

    1. 背景 在之前介绍MySQL执行计划的博文中已经谈及了一些关于子查询相关的执行计划与优化.本文将重点介绍MySQL中与子查询相关的内容,设计子查询优化策略,包含半连接子查询的优化与非半连接子查询的 ...

  9. postgresql子查询优化(提升子查询)

    问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...

随机推荐

  1. Linux 重装MySQL

    1.首先查看当前MySQL的安装情况,查找之前是否安装了MySQL rpm -qa|grep -i mysql 可以看到如下图: 因为我是使用的宝塔面板一键安装的LAMP,所以显示安装了bt-mysq ...

  2. k8s-ephemeral和init容器

    截止到目前k8s1.18版本,k8s已经支持四种类型的container:标准容器,sidecar容器,init容器,ephemeral容器. 一:ephemeral容器 1.1.什么是ephemer ...

  3. httpd解析php的小贴士

    以前使用php的时候, 都是直接用nginx和php对接的, 极少是用apache去对接, 但是最近在用httpd测试WordPress的时候, 发现一个有趣的问题, php不用启动也能直接去解析ph ...

  4. 一文带你快速搞懂动态字符串SDS,面试不再懵逼

    目录 redis源码分析系列文章 前言 API使用 embstr和raw的区别 SDSHdr的定义 SDS具体逻辑图 SDS的优势 更快速的获取字符串长度 数据安全,不会截断 SDS关键代码分析 获取 ...

  5. ElasticSearch6.3脚本更新

    使用上篇文章创建的索引进行学习:https://www.cnblogs.com/wangymd/p/11200996.html 官方文档:https://www.elastic.co/guide/en ...

  6. 04.Java基础语法

    一.Java源程序结构与编程规范 一个完整的Java源程序应该包含下列部分 package语句,至多一句,必须放在源程序第一句 import语句,没有或者若干句,必须放在所有类定义前 public c ...

  7. count(1) AND count(*) 对比

    相信很多小伙伴都想知道count(1) 和 count(*) 的速度问题 ,今天我给大家做一下测试.我这里测试的是MySql数据库 声明:测试之前 我数据库表里面有100万条数据.我们先来测试coun ...

  8. Jquery封装:下拉框插件

    代码如下: ;(function ($, window) { $.fn.addSelect = function (options) { //合并传入与默认的参数 var opts = $.exten ...

  9. 了解Nginx与PHP的交互?

    Nginx可以接收请求并转发给PHP-FPM. 1.开始深入Nginx与FastCGI协议 通过对Nginx新增Server配置实现了nginx与PHP的一次通信,配置文件非常简单. 从上图的Ngin ...

  10. SSM-maven 简单整合

    记一次简单的整合了一次SSM框架过程,因为好久不用了在过程中发生了一些问题. 后续我会在继续在此基础上整合其他框架进来. 本次整合用到的框架有: spring & springmvc myba ...