MySQL实验 子查询优化双参数limit
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有索引
实验过程
老版本explain推荐参考博客(即新版本默认explain extended)
使用未优化双参数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,我们可以借助覆盖索引的方式优化查询效率。
最后的补充
仅对于双参数limit的优化,除了子查询外还有以下方法:
倒排表优化法
倒排表法类似建立索引,用一张表来维护页数,然后通过高效的连接得到数据。缺点:只适合数据数固定的情况,数据不能删除,维护页表困难
反向查找优化法
当偏移超过一半记录数的时候,先用排序,这样偏移就反转了
缺点:order by优化比较麻烦,要增加索引,索引影响数据的修改效率,并且要知道总记录数
偏移大于数据的一半
limit偏移算法:
正向查找: (当前页 – 1) * 页长度
反向查找: 总记录 – 当前页 * 页长度
有时间在进行实验
MySQL实验 子查询优化双参数limit的更多相关文章
- Mysql in子查询中加limit报错
Mysql in子查询中加limit报错 select id from aa where id in ( select id from bb limit 10 ); 改写成 SELECT id FRO ...
- MySQL实验 内连接优化order by+limit 以及添加索引再次改进
MySQL实验 内连接优化order by+limit 以及添加索引再次改进 在进行子查询优化双参数limit时我萌生了测试更加符合实际生产需要的ORDER BY + LIMIT的想法,或许我们也可以 ...
- centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课
centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数 ...
- Mysql单表访问方法,索引合并,多表连接原理,基于规则的优化,子查询优化
参考书籍<mysql是怎样运行的> 非常推荐这本书,通俗易懂,但是没有讲mysql主从等内容 书中还讲解了本文没有提到的子查询优化内容, 本文只总结了常见的子查询是如何优化的 系列文章目录 ...
- 【MySQL】MySQL中针对大数据量常用技术_创建索引+缓存配置+分库分表+子查询优化(转载)
原文地址:http://blog.csdn.net/zwan0518/article/details/11972853 目录(?)[-] 一查询优化 1创建索引 2缓存的配置 3slow_query_ ...
- mysql数据库sql优化——子查询优化
1.什么是子查询.表关联查询: 子查询:是指在主sql语句中的select或where子句中使用select查询语句:select a.name,(select b.name from b where ...
- 浅谈MySQL中的查询优化
mysql的性能优化包罗甚广: 索引优化,查询优化,查询缓存,服务器设置优化,操作系统和硬件优化,应用层面优化(web服务器,缓存)等等.这里的记录的优化技巧更适用于开发人员,都是从网络上收集和自己整 ...
- 聊聊MySQL的子查询
1. 背景 在之前介绍MySQL执行计划的博文中已经谈及了一些关于子查询相关的执行计划与优化.本文将重点介绍MySQL中与子查询相关的内容,设计子查询优化策略,包含半连接子查询的优化与非半连接子查询的 ...
- postgresql子查询优化(提升子查询)
问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...
随机推荐
- 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)
系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...
- .NET Core 工作单元unitofwork 实现,基于NPOCO
现有项目中的orm 并非efcore,而是非主流的npoco,本身没有自带工作单元所以需要自己手撸一个,现记录一下,基于其他orm的工作单元照例实现应该没有什么问题 该实现基于NPOCO,针对其他的O ...
- [原创][开源] SunnyUI.Net 主题
SunnyUI.Net, 基于 C# .Net WinForm 开源控件库.工具类库.扩展类库.多页面开发框架 Blog: https://www.cnblogs.com/yhuse Gitee: h ...
- 00-03.kaliLinux-vi粘贴复制功能配置
KaliLinux在xShell的vim中默认是无法复制和粘贴的,需要做如下配置后才能使用: 方法一 进入vim命令行模式,输入: :set mouse=c #进入Command-line 模式 然后 ...
- 09.Django-数据库优化
Django查询数据库性能优化 现在有一张记录用户信息的UserInfo数据表,表中记录了10个用户的姓名,呢称,年龄,工作等信息. models文件 from django.db import mo ...
- call,apply,bind的理解
2020-03-19 call,apply,bind的理解 先说区别call, apply基本上没什么不一样,唯一不一样的地方是传参方式不同 但是bind和call,apply有区别.bind是重新绑 ...
- (四)log4j同配置下多个进程写日志
原文链接:https://blog.csdn.net/voiceofwind/article/details/51966361 由于起了两个不同的任务,log4j中用的是一套配置,写入的是同一个路径, ...
- URL is not registered (Settings | Languages & Frameworks | Schemas and DTDs)
File - Settings - Schemas and DTDS时,选中报错的地址,然后Ctrl+alt+s打开设置(或者右键 -> setting)找到 把报错的地址填入就可以了,最后应用 ...
- MQ消息队列(1)—— 概念和使用场景
一.什么是消息队列 消息即是信息的载体.为了让消息发送者和消息接收者都能够明白消息所承载的信息(消息发送者需要知道如何构造消息:消息接收者需要知道如何解析消息),它们就需要按照一种统一的格式描述消息 ...
- JavaWeb网上图书商城完整项目--day02-7.提交注册表单功能之流程分析
1.点击注册之后将提交的信息传递到UserServlet的public String regist方法进行处理,然后将东西通过service进行处理 业务流程: