-- 示例表
CREATE TABLE `employees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
`age` int(20) NOT NULL DEFAULT '0' COMMENT '年龄',
`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '入职时间',
PRIMARY KEY (`id`),
KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE,
KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=136326 DEFAULT CHARSET=utf8 COMMENT='员工表' --创建100000条记录
drop procedure if EXISTS insert_emp;
delimiter ;;
create procedure insert_emp()
BEGIN
declare i int;
set i=1;
while(i < 100000)DO
INSERT INTO employees(name,age,position) values(CONCAT('xiaoqiang',i),i,'coder');
SET i=i+1;
end WHILE;
end;;
delimiter ;
call insert_emp();

根据自增且连续的主键排序的分页查询

select * from employees LIMIT 9999 ,5;





表示从表employees 中取出从10000行开始的5行记录。看似只查询5条记录,实际这条SQL是先读取10005条记录,然后抛弃前10000条记录,然后读到后面5条想要的数据。没有添加单独的order by,表示通过主键排序。

因此要查询一张大表比较靠后的数据,执行效率是非常低的。

因为主键是自增且连续的,所以可以改写成按照主键查询从第10001开始的五行数据,如下:

select * from  employees WHERE id > 9999 limit 5;





可以看到两个sql的执行计划,显然改写后的sql走了索引,而且扫描的行数大大减少,执行效率会更高。但是,这条改写的sql在很多场景下并不实用,因为表中可能某些记录被删除后,主键空缺,导致结果不一致。

先删除一条记录,然后测试下原来sql和优化后的sql:

select * from employees LIMIT 9999 ,5;

 select * from employees where id> 9999 limit 5;



两条sql的结果不一样,因此,如果主键不连续,不能使用上面描述的方法。

另外由于原来sql是order by非主键字段,按照上面的方法改写sql的结果不一致。所以这种改写得满足以下两个条件:

  • 主键自增且连续
  • 结果是按照主键排序的

根据非主键字段排序的分页查询

select * from employees order by name limit 9000, 5;

 explain select * from employees order by name limit 9000, 5;

key字段对应的值为null,发现并没有使用name字段的索引。因为扫描整个索引并查找到没有索引的行,可能要便利多个索引树,其成本比扫描全表的成本更高,索引优化器放弃使用索引。

优化的关键是:让排序时返回的字段尽可能的少,所以可以让排序和分页操作先查出主键,然后根据主键查到对应的记录。

改下如下:

select * from employees as e inner join(select id from employees order by name limit 9000,5) as ed on e.id=ed.id;



可以看到结果与原来的sql结果是一致的,执行时间减少了一般以上,再对比下执行计划:



原来的sql使用的是filesort排序,而优化后的sql使用的是索引排序。

in和exists优化

原则:小表驱动大表,即小表的数据集驱动大表的数据集

in:当B表的数据集小于A表的数据集时,in由于exists

select * from A where id in(select id from B)
等价于
for(select id from B){
select * from A where A.id=B.id
}

exists:当A表的数据集小于B表的数据集时,exitsts优于in

当著查询A的数据,放到子查询B中做条件验证,根据验证结果(true或false)来决定著查询的数据是否保留。

select * from A  exists(select 1 from B where A.id=B.id)

等价于
for(select * from A){
select * from B where A.id=B.id
}

count(*)查询优化

explain select count(1) from employees;
explain select count(id) from employees;
explain select count(name) from employees;
explain select count(*) from employees;



四个sql的执行计划几乎一样的,count(name)使用的是联合索引, 主要区别根据某个字段做count操作不会统计字段为null的值的数据行。

除了count(name)的其他count操作,都是用的辅助索引而不是主键索引, 因为二级索引存储数据更少,检索性能更高。

还没关注我的公众号?

  • 扫文末二维码关注公众号【小强的进阶之路】可领取如下:
  • 学习资料: 1T视频教程:涵盖Javaweb前后端教学视频、机器学习/人工智能教学视频、Linux系统教程视频、雅思考试视频教程;
  • 100多本书:包含C/C++、Java、Python三门编程语言的经典必看图书、LeetCode题解大全;
  • 软件工具:几乎包括你在编程道路上的可能会用到的大部分软件;
  • 项目源码:20个JavaWeb项目源码。

工作中遇到的99%SQL优化,这里都能给你解决方案(三)的更多相关文章

  1. 工作中遇到的99%SQL优化,这里都能给你解决方案

    前几篇文章介绍了mysql的底层数据结构和mysql优化的神器explain.后台有些朋友说小强只介绍概念,平时使用还是一脸懵,强烈要求小强来一篇实战sql优化,经过周末两天的整理和总结,sql优化实 ...

  2. 工作中遇到的99%SQL优化,这里都能给你解决方案(二)

    -- 示例表 CREATE TABLE `employees` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL ...

  3. 收集一些工作中常用的经典SQL语句

    作为一枚程序员来说和数据库打交道是不可避免的,现收集一下工作中常用的SQL语句,希望能给大家带来一些帮助,当然不全面,欢迎补充! 1.执行插入语句,获取自动生成的递增的ID值 INSERT INTO ...

  4. 在工作中常用到的SQL

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 最近在公司做了几张报表,还记得刚开始要做报表的时候都 ...

  5. 工作中常用到的sql命令!!!

    一.mysql数据库日常操作.     1.启动mysql:/etc/init.d/mysql start (前面为mysql的安装路径)     2.重启mysql:  /etc/init.d/my ...

  6. 工作中遇到的一道SQL应用题

    登录日志表 CREATE TABLE [dbo].[LoginLog]([Seq] [int] NOT NULL IDENTITY(1, 1),  --Seq[UserId] [varchar] (2 ...

  7. 分享一个工作中遇得到的sql(按每天每人统计拖车次数与小修次数)

    查询每人每天的数据 首先先建表 CREATE TABLE `user` ( `name` ) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CR ...

  8. 《高性能SQL调优精要与案例解析》一书谈SQL调优(SQL TUNING或SQL优化)学习

    <高性能SQL调优精要与案例解析>一书上市发售以来,很多热心读者就该书内容及一些具体问题提出了疑问,因读者众多外加本人日常工作的繁忙 ,在这里就SQL调优学习进行讨论并对热点问题统一作答. ...

  9. Oracle SQl优化总结

    对数据库技术的热爱是我唯一的安慰,毕竟这是自己喜欢的事情,还可以做下去. 因为客户项目的需要,我又开始接触Oracle,大部分工作在工作流的优化和业务数据的排查上.为了更好的做这份工作,我有参考过or ...

随机推荐

  1. [nghttp2]压测工具,源码编译并进行deb打包过程

    编译环境:deepin 15.11桌面版 nghttp2下载地址:https://github.com/nghttp2/nghttp2 环境要求 emm只能在类Linux环境才能完整编译,想在Wind ...

  2. 使用 Docker 生成 Let’s Encrypt 证书

    概念 什么是 Container ? https://www.docker.com/resources/what-container https://www.docker.com/why-docker ...

  3. 万万没想到,JVM内存结构的面试题可以问的这么难?

    在我的博客中,之前有很多文章介绍过JVM内存结构,相信很多看多我文章的朋友对这部分知识都有一定的了解了. 那么,请大家尝试着回答一下以下问题: 1.JVM管理的内存结构是怎样的? 2.不同的虚拟机在实 ...

  4. git常用指令整理

    git常用指令一览表 GIT指令 说明 git add . 将全部文件的内容加到Git索引以便执行commit. 这个指令不会检查文件夹中是否有文件被删除. 要注意的是,只有执行" git ...

  5. 8.15 day33 进程池与线程池_协程_IO模型(了解)

    进程池和线程池 开进程开线程都需要消耗资源,只不过两者比较的情况线程消耗的资源比较少 在计算机能够承受范围之内最大限度的利用计算机 什么是池? ​ 在保证计算机硬件安全的情况下最大限度地利用计算机 ​ ...

  6. .Net Mvc过滤器观察者模式记录网站报错信息

    基本介绍: 观察者模式是一种对象行为模式.它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.在观察者模式中,主题是通知的发布者,它发出通知时并不 ...

  7. php opcodes(vld)翻译教程

    一.php opcodes的由来(如果你只想知道如何解php opcodes就直接跳过这步) 1.PHP内核-Zend引擎的详解:https://www.php.cn/php-weizijiaoche ...

  8. 十款强大的IDEA插件-Java开发者的利器

    xl_echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!! 插 ...

  9. numba,让python速度提升百倍

    python由于它动态解释性语言的特性,跑起代码来相比java.c++要慢很多,尤其在做科学计算的时候,十亿百亿级别的运算,让python的这种劣势更加凸显. 办法永远比困难多,numba就是解决py ...

  10. 关于selenium自动化对窗口句柄的处理

    首先什么是句柄?句柄就是你点击一个页面,跳转了一个新的窗口.你要操作的元素可能在原窗口上,也有可能在新窗口上. 看下图句柄1 句柄2 由这2张图可知,url不一样,证明他们是处于不同的界面,我要操作的 ...