MySQL - 分页查询优化的两个案例解析
文章目录
- 生猛干货
- Table
- 日常场景
- Case1 根据自增且连续的主键排序的分页查询
- 优化
- 数据可删除的场景
- 适用条件
- Case2 根据非主键字段排序的分页查询
- 搞定MySQL
生猛干货
带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试
Table
还是我们那个老表
CREATE TABLE `employees` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',PRIMARY KEY (`id`),KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='员工记录表';
有个主键索引和二级联合索引 idx_name_age_position
日常场景
任何一个系统,分页查询都是必不可少的吧 ,MySQL中的分页查询 就是 limit呗 ,你有没有感觉到 越往后翻页越慢 ,常见的SQL如下
mysql> select * from employees limit 10000,10;
就是从 employees 中取出从 10001 行开始的 10 行记录。
MySQL是怎么处理这个SQL的呢?
先读取 10010 条记录,然后抛弃前 10000 条记录,仅保留10 条想要的数据 。 可想而知,如果要查询一张大表比较靠后的数据,这效率是非常低的。
那有没有优化的办法呢?
Case1 根据自增且连续的主键排序的分页查询
我们先来看一个 【根据自增且连续主键排序的分页查询】的优化案例
select * from employees limit 10000, 10
从第1万条数据开始,获取10条数据
我们来看下执行计划
mysql> explain select * from employees limit 10000, 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 | 100175 | 100 | NULL |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
1 row in setmysql>
因为没有添加单独 order by字段,所以表示通过主键排序 。 执行计划显示全表扫描
优化
如何优化下呢?
既然是按照id排序,结合B+Tree 的特性 ,如果能从 10000这个数据位置往后扫描,是不是就会比扫描全部理论上更快一些呢?
改造如下
select * from employees where id> 10000 limit 10;
来看下执行计划
mysql> explain select * from employees where id> 10000 limit 10;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+-------+----------+-------------+
| 1 | SIMPLE | employees | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 50087 | 100 | Using where |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+-------+----------+-------------+
1 row in set
比一比这两个,是不是下面那个更快一些
数据可删除的场景
还有个问题,我们知道我们业务系统有些数据是可以被删除的,如果有些数据被删除了,还是按照id来排序,上面这种优化方式,会存在问题吗?
假设8888 这条业务数据被删除了
delete from employees where id = 8888 ;
那我们来看下
如果允许删除,那这种优化方式是不是就不正确了?
limit 10000, 10 : 就是全部数据排好序后 取第10000个开始后的10个,我们刚才删除了8888, 所以 第一条数据就变成了 10002
id> 10000 limit 10 : 这个就很好理解了,删除了8888 ,不影响 id>10000的排序 ,所以第一条数据还是 10001
适用条件
如果主键不连续,不能使用上面描述的优化方法。
如果原 SQL 是 order by 非主键的字段,按照上的方法改写会导致两条 SQL 的结果不一致。
所以这种优化方式必须同时满足以下两个条件:
- 主键自增且连续
- 结果是按照主键排序的
Case2 根据非主键字段排序的分页查询
来看第二个案例,实际工作中可能比第一种用的比较多
select * from employees ORDER BY name limit 10000, 10 ;
来看下执行计划
mysql> explain select * from employees ORDER BY name limit 10000, 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 | 100175 | 100 | Using filesort |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
1 row in setmysql>
按照B+Tree的结构,应该会走name字段索引,wtf , 操作的结果集太多,又要回表等等原因 , MySQL可能不选name 字段的索引 , key 字段对应的值为 null ,从而走了全表扫描 。。。。
还有 Using filesort
这部分就属于MySQL内部的优化了,可以使用Trace来追踪下MySQL是如何选择的 ,
MySQL - 使用trace工具来窥探MySQL是如何选择执行计划的
MySQL认为扫描整个索引并查找到没索引的行(可能要遍历多个索引树)的成本比扫描全表的成本更高,所以优化器放弃使用索引。
那既然知道不走索引的原因,那么怎么优化呢?
关键是让排序时返回的字段尽可能少,所以可以让排序和分页操作先查出主键,然后根据主键查到对应的记录.
让排序时返回的字段尽可能少–》 只返回id , 然后用返回的特定范围的id ,再和原表关联,只取特定范围内的数据 ,肯定比全表扫描要快。
改造如下
select * from employees a inner join (select id from employees order by name limit 10000,10) b on a.id = b.id;
先找到id (select id 使用覆盖索引),然后用这个结果集 (这个案例中就只有10条结果)去和 employees 关联
看看执行计划
原 SQL 使用的是 filesort 排序,优化后的 SQL 使用的是索引排序。
当然了,结果集也是和优化前是一致的
搞定MySQL
MySQL - 分页查询优化的两个案例解析相关推荐
- 记一个mysql分页查询优化试验
问题 分页查询的时候,如果直接 select 字段1,字段2,...,字段n from 表名 limit offset,pageSize,会随着offset增大越来越慢. 解决思路 通过查看执行计划是 ...
- mysql分页查询_4种MySQL分页查询优化的方法,你知道几个?
前言 当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点.下面简单说一下我知道的 ...
- C#比较两个日期的大小两种案例解析
方法1: DateTime.Compare(t1,t2)比较两个日期大小,排前面的小,排在后面的大,比如:2011-2-1就小于2012-3-2 返回值小于零: t1 小于 t2. 返回值等于零 ...
- Mysql 给你100万条数据的一张表,你将如何分页查询优化?
1.两种查询引擎查询速度(myIsam 引擎 ) InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行. ...
- mysql uuid分页优化_MySQL性能优化之分页查询优化
MySQL分页查询原理 MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么 ...
- 刘子佼 mysql 下载_MySQL数据管理之备份恢复案例解析 23讲 Mysql备份恢复实战 视频教程...
课程名称:MySQL数据管理之备份恢复案例解析 23讲 Mysql备份恢复实战课程简介: 课程独家解析MySQL 5.6最新特性,课程讲师刘子佼讲课风格幽默,善于与人沟通,善于组建和协调团队攻克技术难 ...
- EF获取多个数据集以及MySQL分页数据查询优化
背景:MySQL分页查询语句为 SELECT * FROM TABLE LIMIT 0,10; 一般页面还会获取总条数,这时候还需要一条查询总条数语句 SELECT COUNT(*) FROM TAB ...
- 关于Visual C#.NET数据库开发经典案例解析(附光盘两张)(珍藏版)—的读后感...
关于Visual C#.NET数据库开发经典案例解析(附光盘两张)(珍藏版)- 评论 读后感:里面的内容很经典,很实用 读后感:给初学者是好,但是是比较旧的了!VS2003 C/S的 读后感:< ...
- mysql分页总页数算法解析_详解MySQL的limit用法和分页查询语句的性能分析
limit用法 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table LIMIT ...
最新文章
- 学习C#要养成的好习惯
- centos中rabbitmq的安装及php支持
- opencv随机数的产生
- 微软服务器在电脑上怎么打开,怎么在一个电脑上开启服务器可以让另外一台电脑连接服...
- 老郭的《Dalvik虚拟机垃圾收集机制简要介绍和学习计划》
- servlet异步_如何使用异步Servlet来提高性能
- 转 python测试框架最全资源汇总
- nodejs版本更新问题:express不是内部或外部命令
- 2021 互联网公司时薪排行榜出炉!微软、美团很不错
- Java Web开发之一:用好的技术设计来犒赏自己
- iOS下载文件,保存路径. 防止加到iCloud备份
- react组件卸载调用的方法_react相关基础知识
- 用 tf.data 加载图片
- Python数据处理Tips机器学习中文数据8种常用处理方法
- 牡丹-洛阳牡丹:洛阳牡丹
- Docker 中文文档(译)
- oracle入门操作3(关于查询 )
- java常见问题incompatible types
- 项目提示JDK版本问题或者语言级别问题时的解决办法
- 使用Python将mat文件转换为npy文件
热门文章
- printf,fprintf(stdout,stderr),sprintf等的使用方法及区别
- hardfault常见原因_XMC实验分享之四十八: Cortex M0的Hard Fault发生原因
- java字符串转化为数组_Go 语言字符串和数组转化 | 臭大佬
- 集成学习(一)—预备知识:分类树和回归树
- Python--读取csv文件的整列
- LeetCode-剑指 Offer 14- I. 剪绳子
- numpy.argmax详解
- 详解Numpy的广播机制
- 数据扩展性探讨和总结--转
- 马云:员工的离职原因--转载