文章目录

  • 生猛干货
  • 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 - 分页查询优化的两个案例解析相关推荐

  1. 记一个mysql分页查询优化试验

    问题 分页查询的时候,如果直接 select 字段1,字段2,...,字段n from 表名 limit offset,pageSize,会随着offset增大越来越慢. 解决思路 通过查看执行计划是 ...

  2. mysql分页查询_4种MySQL分页查询优化的方法,你知道几个?

    前言 当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点.下面简单说一下我知道的 ...

  3. C#比较两个日期的大小两种案例解析

    方法1: DateTime.Compare(t1,t2)比较两个日期大小,排前面的小,排在后面的大,比如:2011-2-1就小于2012-3-2 返回值小于零:  t1 小于 t2.  返回值等于零  ...

  4. Mysql 给你100万条数据的一张表,你将如何分页查询优化?

    1.两种查询引擎查询速度(myIsam 引擎 ) InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行. ...

  5. mysql uuid分页优化_MySQL性能优化之分页查询优化

    MySQL分页查询原理 MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么 ...

  6. 刘子佼 mysql 下载_MySQL数据管理之备份恢复案例解析 23讲 Mysql备份恢复实战 视频教程...

    课程名称:MySQL数据管理之备份恢复案例解析 23讲 Mysql备份恢复实战课程简介: 课程独家解析MySQL 5.6最新特性,课程讲师刘子佼讲课风格幽默,善于与人沟通,善于组建和协调团队攻克技术难 ...

  7. EF获取多个数据集以及MySQL分页数据查询优化

    背景:MySQL分页查询语句为 SELECT * FROM TABLE LIMIT 0,10; 一般页面还会获取总条数,这时候还需要一条查询总条数语句 SELECT COUNT(*) FROM TAB ...

  8. 关于Visual C#.NET数据库开发经典案例解析(附光盘两张)(珍藏版)—的读后感...

    关于Visual C#.NET数据库开发经典案例解析(附光盘两张)(珍藏版)- 评论 读后感:里面的内容很经典,很实用 读后感:给初学者是好,但是是比较旧的了!VS2003 C/S的 读后感:< ...

  9. mysql分页总页数算法解析_详解MySQL的limit用法和分页查询语句的性能分析

    limit用法 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table LIMIT ...

最新文章

  1. 学习C#要养成的好习惯
  2. centos中rabbitmq的安装及php支持
  3. opencv随机数的产生
  4. 微软服务器在电脑上怎么打开,怎么在一个电脑上开启服务器可以让另外一台电脑连接服...
  5. 老郭的《Dalvik虚拟机垃圾收集机制简要介绍和学习计划》
  6. servlet异步_如何使用异步Servlet来提高性能
  7. 转 python测试框架最全资源汇总
  8. nodejs版本更新问题:express不是内部或外部命令
  9. 2021 互联网公司时薪排行榜出炉!微软、美团很不错
  10. Java Web开发之一:用好的技术设计来犒赏自己
  11. iOS下载文件,保存路径. 防止加到iCloud备份
  12. react组件卸载调用的方法_react相关基础知识
  13. 用 tf.data 加载图片
  14. Python数据处理Tips机器学习中文数据8种常用处理方法
  15. 牡丹-洛阳牡丹:洛阳牡丹
  16. Docker 中文文档(译)
  17. oracle入门操作3(关于查询 )
  18. java常见问题incompatible types
  19. 项目提示JDK版本问题或者语言级别问题时的解决办法
  20. 使用Python将mat文件转换为npy文件

热门文章

  1. printf,fprintf(stdout,stderr),sprintf等的使用方法及区别
  2. hardfault常见原因_XMC实验分享之四十八: Cortex M0的Hard Fault发生原因
  3. java字符串转化为数组_Go 语言字符串和数组转化 | 臭大佬
  4. 集成学习(一)—预备知识:分类树和回归树
  5. Python--读取csv文件的整列
  6. LeetCode-剑指 Offer 14- I. 剪绳子
  7. numpy.argmax详解
  8. 详解Numpy的广播机制
  9. 数据扩展性探讨和总结--转
  10. 马云:员工的离职原因--转载