Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

33 | MySQL调优之SQL语句:如何写出高性能SQL语句?

刘超 2019-08-06
你好,我是刘超。
从今天开始,我将带你一起学习 MySQL 的性能调优。MySQL 数据库是互联网公司使用最为频繁的数据库之一,不仅仅因为它开源免费,MySQL 卓越的性能、稳定的服务以及活跃的社区都成就了它的核心竞争力。
我们知道,应用服务与数据库的交互主要是通过 SQL 语句来实现的。在开发初期,我们更加关注的是使用 SQL 实现业务功能,然而系统上线后,随着生产环境数据的快速增长,之前写的很多 SQL 语句就开始暴露出性能问题。
在这个阶段中,我们应该尽量避免一些慢 SQL 语句的实现。但话说回来,SQL 语句慢的原因千千万,除了一些常规的慢 SQL 语句可以直接规避,其它的一味去规避也不是办法,我们还要学会如何去分析、定位到其根本原因,并总结一些常用的 SQL 调优方法,以备不时之需。
那么今天我们就重点看看慢 SQL 语句的几种常见诱因,从这点出发,找到最佳方法,开启高性能 SQL 语句的大门。

慢 SQL 语句的几种常见诱因

1. 无索引、索引失效导致慢查询

如果在一张几千万数据的表中以一个没有索引的列作为查询条件,大部分情况下查询会非常耗时,这种查询毫无疑问是一个慢 SQL 查询。所以对于大数据量的查询,我们需要建立适合的索引来优化查询。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(24)

  • 张学磊
    status和create_time单独建索引,在查询时只会遍历status索引对数据进行过滤,不会用到create_time列索引,将符合条件的数据返回到server层,在server对数据通过快排算法进行排序,Extra列会出现file sort;应该利用索引的有序性,在status和create_time列建立联合索引,这样根据status过滤后的数据就是按照create_time排好序的,避免在server层排序

    作者回复: 非常准确!

    2019-08-06
    3
    22
  • Kian.Lee
    我在实际项目中使用“select order_no from order where status =1 order by id desc
    ” 代替此功能,id为bigint ,也少维护一个索引(create_time)😁
    2019-08-08
    1
    4
  • Jian
    因为好久没有做SQL相关的开发了,所以开始没有特别明白【利用子查询优化分页查询】这里面的意思。我来说下自己的想法,请您检证。我看到您贴的截图中,优化后的sql语句,扫描的行数(rows列)分别是90409和10001,多余前一个较慢的查询,可见扫描行数,不是这个性能的主要原因。我推测这个是由于limit [m],n的实现方法导致的,即MySql会把m+n的数据都取出来,然后返回n个数据给用户。如果用第二种SQL语句,子查询只是获得一个id,虽然扫描了很多行,但都是在索引上进行的,切不需要回表获取内容。外查询是根据id获取数据20条内容,速度自然就会快了。我认为这里性能提高的原因还是居于索引的恰当使用。

    作者回复: 可以这么理解

    2019-08-12
    3
  • QQ怪
    对staus和create_time建立联合索引

    作者回复: 对的,为了避免文件排序的发生。因为查询时我们只能用到status索引,如果要对create_time进行排序,则需要使用文件排序filesort。

    filesort是通过相应的排序算法将取得的数据在内存中进行排序,如果内存不够则会使用磁盘文件作为辅助。虽然在一些场景中,filesort并不是特别消耗性能,但是我们可以避免filesort就尽量避免。

    2019-08-06
    1
    2
  • 迎风劲草
    创建 status create_time order_no 联合索引,避免回表

    作者回复: 建立联合索引没错,还有就是避免文件排序的问题。

    2019-08-06
    1
    2
  • mumu

    select * from `demo`.`order` where id> (select id from `demo`.`order` order by order_no limit 10000, 1) limit 20;,老师您好,我不懂这样写为什么是正确的,为什么id>子查询结果的20条就是按order_no排序所需的20条?

    作者回复: 这里我们就默认orderno是递增的,而且是随着id自增长递增

    2019-11-04
  • 张三丰
    就算使用了联合索引,也避免不了排序吧,因为题目要求的是降序,联合索引是保证第一个索引有序的前提下再保证第二个索引有序,那么这个有序是升序,如果没记错的话。

    作者回复: 只要有序的,就不会再重复排序了,只是一个升降序的问题了

    2019-10-04
  • 疯狂咸鱼
    为什么分页查询优化那块,主查询扫描这么多行?

    作者回复: 使用limit 10000,1,所以需要顺序扫描到10001行,所以我们尽量使用主键递增的方式,直接将主查询换成select * from `demo`.`order` where id> 10000 limit 20,避免扫描带来的性能问题。

    2019-09-26
  • 风轻扬
    select * from `demo`.`order` where id> (select id from `demo`.`order` order by order_no limit 10000, 1) limit 20;
    老师,这个优化后的查询,您是先查询出来的第10001条数据的id,然后 id 大于此值。获取20条数据。这样获取的值不对啊,我试了。这样获取的是10002到10021的数据了,不是10001到10020的数据。子查询获取的值减一就对了

    作者回复: >=即可,强调优化思路,具体的细节老师这边没有把控好,多多包涵

    2019-09-20
  • man1s
    创建create_time + status 的组合索引
    问:老湿,执行计划中的const/system 你说B+树的第一层就可以返回,可是只有叶子节点才存储数据呀

    作者回复: 这里解释的有问题,已修正,是一个匹配行。

    2019-09-16
  • godtrue
    课后思考及问题
    1:按照效率排序的话,count(字段)<count(主键 id)<count(1)≈count(*),所以我建议你,尽量使用 count(*)。——MySQL,丁奇老师的结论
    如果对一张大表经常做 SELECT COUNT(*) 操作,这肯定是不明智的。——刘老师的结论
    同样的问题,不同的老师给出了截然相反的结论,我希望有一天两位老师可以讨论一下为什么?
    刘老师具体没讲COUNT(*)的原理,我倾向于认为丁奇老师的结论是正确的。

    作者回复: 我与丁奇结论没有相反,丁奇是建议你在这些count类型中选择使用count(*),而我是建议不要在大表中做count(*)。丁奇老师讲解了COUNT(*)的原理,我相信他也会建议你不要在一个大表中频繁COUNT(*)。

    2019-09-14
    1
  • 大俊stan
    count(*) 的速度是最快的innodb自己有优化
    2019-09-08
  • 张德
    没看别人评论 我来说一下 直接查状态为1的订单 索引的区分度太低

    作者回复: 答案已给出

    2019-08-28
  • 陈影
    select * from `demo`.`order` where id> (select id from `demo`.`order` order by order_no limit 10000, 1) limit 20;
    老师,这个子查询找到了按照order_no排序第10001行数据的id,这个id是按照这种排序递增的吗?主查询是怎么找到这种排序方式下第10001-10020行数据的?

    作者回复: 这个id是自增长id

    2019-08-26
  • JackJin
    感觉要建立联合索引,但不知具体原因

    作者回复: 为了避免文件排序的发生。因为查询时我们只能用到status索引,如果要对create_time进行排序,则需要使用文件排序filesort。

    2019-08-09
  • Geek_002ff7
    真实情况一般不会在status上单独建索引,因为status大部分都是重复值,数据库一般走全表扫描了,感觉漏讲了索引失效的情况

    作者回复: 下一讲则会讲到

    2019-08-09
  • 东方奇骥
    select * from `demo`.`order` order by order_no limit 10000, 20;
    select * from `demo`.`order` where id> (select id from `demo`.`order` order by order_no limit 10000, 1) limit 20; 老师,感觉自己没完全弄明白,就是用子查询快那么多,但是子查询里,不是也要扫描10001行?还是说子查询里只查了id,不需要回行,所以速度快?

    作者回复: 这个涉及到返回记录的大小,前者会返回10020条行记录,而后者只返回20条记录。

    2019-08-08
    2
  • LW
    order_no创建主键,status+create_time创建联合索引

    作者回复: 对的

    2019-08-06
    1
  • 撒旦的堕落
    订单状态字段的离散度很低 不适合做索引
    因为离散度低 而又没有分页 所以当表数据量大的时候 查询出来的数量也有可能很大
    创建时间倒序 可以换成主键倒序 去除掉时间字段的索引
    根据状态查询 个人觉得可以从业务入手 将相同状态的数据保存到一张表 想听听老师的意见

    作者回复: 这里主要是filesort问题

    2019-08-06
  • nimil
    select * from table limit 1 这种sql语句会走主键索引么,我看explain里边没有任何索引记录

    作者回复: 不会,没有使用到索引。

    2019-08-06
收起评论
24
返回
顶部