于2023.3.17日重写,之前写的还是太八股文太烂了一点逻辑都没有,这次重新写了之后,感觉数据库优化还是很有必要的,之前觉得不必要是我年轻了。

一、如何定位慢SQL语句

1、通过慢查询日志查询已经执行完的SQL语句

默认慢查询日志不会开启,需要手动设置,命令为

mysql> set global slow_query_log = on;

也可以根据业务设置时间阈值以及查看慢查询日志的存储位置和文件名,自行百度

然后可以通过查询日志的方式,定位到慢SQL语句,比如使用tail命令

2、通过processlist查看正在执行的慢SQL语句

这个没什么好说的,在mysql>终端中,使用show processlist指令或者show full processlist

二、如何分析慢SQL语句

使用老朋友explain关键字explain+分析的sql语句即可,一般来说,我们需要重点关注selectType,type、rows、extra、key。

关键字 含义 常见
selectType 查询类型 simple,primary,union
type 表连接类型 ref,index,range,all
rows 预计需要扫描的行数 是估值
key 实际使用的索引
extra 附加信息 Using index,Using temporary,using filesort

三、分析慢SQL语句的原因

1、大部分慢SQL语句优化都跟索引有关系,查看是不是索引设置不合理,索引失效等问题

2、一部分是sql语句本身有关系,比如深分页,in元素过多,对非索引字段进行排序等,可以考虑优化sql语句

3、小部分与sql语句无关,比如大数据表的查询确实会比较慢

四、常见的SQL优化

  1. 优化Order By

首先,我们先知道Order by是如何实现的,order by的功能我们都知道,就是使用By后面的一个或者多个字段进行排序,我们假设现在有这么一个需求,对周杰伦的歌曲按照播放量进行排序,查出歌手,歌曲编码,歌曲曲风,播放量等播放,很容易写出来

select singer,song_code,song_types,conuts FROM `song` where singer='周杰伦' order by counts

我们假设对singer字段加了一个索引,这样避免全表扫描,那么这条sql语句应该是这样执行的。

a. 初始化sort_buffer,放入所有select字段(可以理解是在sort_buffer这块内存中初始了select所需字段的一张表)

b. 从索引singer 找出第一条满足singer是周杰伦的行记录的主键(不懂的同学可以看下辅助索引的概念,简单来说非主键索引的B+树叶子节点是主键索引),根据主键进行回表 取出select所需的字段放入sort_buffer中

c. 重复b操作,直到所有满足条件的记录放入sort_buffer中了,然后sort_buffer内部根据字段counts进行快速排序,返回结果

以上这种实现方式,叫做全字段排序,观察这种实现方式,它的特点就是要把select的所有字段放入sort_buffer中,尽管只需要一个字段进行排序,它的问题也很明显,我用黄色高亮出来了,所有字段都放入sort_buffer中,如果select了好多个字段或者sort_buffer设置的太小(自行百度,没必要记住这种命令),那内存就顶不住了,得靠磁盘中的内部文件帮忙,此时外部文件使用归并排序。

解决这个问题的就是order by的第二种实现方式 rowid排序,这种实现方式也很好理解,就是sort_buffer中只放两种类型的字段,一种就是需要排序的字段,另一种就是主键(一般就是id作为主键),那么sql语句执行方式就不太一样了。

a. 初始化sort_buffer,放入需要排序的字段和id字段

b.根据辅助索引singer找出第一条满足singer是周杰伦的行记录的主键,根据主键进行回表,取出主键id和counts字段放入sort_buffer中

c. 重复b操作,直到所有满足条件的记录放入sort_buffer中了,然后sort_buffer内部根据字段counts进行快速排序

d. 根据排序后的主键id进行回表,取出select需要的字段返回

这就是rowid排序的实现方式,也很明显,这种方式需要两次回表操作,所以并不是一定会比所有字段排序方式好

那如何解决呢?答案页很简单,说到底还是我们的索引设置的不够合理。

对于这种情况优化,我们可以采用设置联合索引的方式进行优化,如果联合索引设置的好,那天然就是有序的了,就没必要进行排序了,同时也可以解决回表问题(索引覆盖),比如针对这个需求,我们可以创建这样的一个联合索引

alter table `song` add index singer_counts_song_code_song_types(singer,counts,song_code,song_types);

注意顺序,singer,counts字段一定要在前两个,如果理解不了的话,要去学习一下联合索引的结构原理。

当然这样做也有局限,比如确实不应该添加索引或者where条件不只有周杰伦也可能是周杰伦和周深的歌曲播放量排名。

  1. llimit深分页优化

limit深分页问题也是大数据领域常见的问题了,很多小白包括我之前并不了解limit的用法,我先简单介绍下limit的用法。 limit offset,n 先是偏移量然后才是真正读取的n条数据,其含义是扫描offset+n条数据然后抛弃前offset条数据,留下最后n条数据。

为什么说深分页不好呢,答案也很简单如果offset很大,那么很大可能会有很多无效的回表,那是因为较多场景其实是利用了辅助索引(例如上面的那个需求,主键就是无意义的id,真正有利用信息的是辅助索引),这么多无效的回表是难以接受的,常见的优化手段有:

我们可以利用子查询优化深分页,这样就避免了回表操作,例如《阿里巴巴java性能调优实战》中的例子

## 需求是返回10000条之后的20条记录
##### 未优化:
select * from `order` order by order_no limit 10000,20
##### 子查询优化:
select * from `order` where id >(select id from `order` order by order_no limit 10000,1) limit 20

id是主键,因此也没有了回表问题

或者如果我们提前知道搜索范围是10001到10020,那么我们就可以直接使用between and范围查询来避免limit深分页问题,当然前提是order by的字段是连续的,而且要知道准确需求范围(很多都是从上次查询的位子开始后n行,这就不行了)

  1. in内元素过多

in本身操作性能就不高,加上元素太多会造成很大的性能浪费,目前我并没有查找到常用的解决方案,我这里给出我常用的方法,如果in里面的元素还是可以枚举的,那么可以尝试union all各个条件select出的结果,如果是不能枚举的,阿里巴巴有个类Mysql的PolarDB mysql有对大量in进行优化 [阿里巴巴文章](PolarDB for MySQL优化器查询变换系列 - IN-List变换 - 陈江的文章 - 知乎 https://zhuanlan.zhihu.com/p/591601424)

五、参考文章

  1. Order By优化
  2. Mysql深分页
  3. Mysql索引

SQL优化---慢SQL优化的更多相关文章

  1. Oracle数据库该如何着手优化一个SQL

    这是个终极问题,因为优化本身的复杂性实在是难以总结的,很多时候优化的方法并不是用到了什么高深莫测的技术,而只是一个思想意识层面的差异,而这些都很可能连带导致性能表现上的巨大差异. 所以有时候我们应该先 ...

  2. SQL Server数据库性能优化技巧

    查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引: 2.I/O吞吐量小,形成了瓶颈效应: 3.内存不足: 4.网络速度慢: 5.查询出的数据量过大: 6.锁或者死锁: 7.返回了不必 ...

  3. 【转】使用SQL Tuning Advisor STA优化SQL

    SQL优化器(SQL Tuning Advisor STA)是Oracle10g中推出的帮助DBA优化工具,它的特点是简单.智能,DBA值需要调用函数就可以给出一个性能很差的语句的优化结果.下面介绍一 ...

  4. 如何用 SQL Tuning Advisor (STA) 优化SQL语句

    在Oracle10g之前,优化SQL是个比较费力的技术活,不停的分析执行计划,加hint,分析统计信息等等.在10g中,Oracle推出了自己的SQL优化辅助工具: SQL优化器(SQL Tuning ...

  5. 【转】MySQL批量SQL插入各种性能优化

    原文:http://mp.weixin.qq.com/s?__biz=MzA5MzY4NTQwMA==&mid=403182899&idx=1&sn=74edf28b0bd29 ...

  6. SQL Server数据库性能优化之SQL语句篇【转】

    SQL Server数据库性能优化之SQL语句篇http://www.blogjava.net/allen-zhe/archive/2010/07/23/326927.html 近期项目需要, 做了一 ...

  7. SQL SERVER 查询性能优化——分析事务与锁(五)

    SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...

  8. SQL Server 查询性能优化 相关文章

    来自: SQL Server 查询性能优化——堆表.碎片与索引(一) SQL Server 查询性能优化——堆表.碎片与索引(二) SQL Server 查询性能优化——覆盖索引(一) SQL Ser ...

  9. Oracle性能优化之SQL语句

    1.SQL语句执行过程 1.1 SQL语句的执行步骤 1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义. 2)语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限. ...

  10. 最有效地优化 Microsoft SQL Server 的性能

      为了最有效地优化 Microsoft SQL Server 的性能,您必须明确当情况不断变化时,性能将在哪些方面得到最大程度的改进,并集中分析这些方面.否则,在这些问题上您可能花费大量的时间和精力 ...

随机推荐

  1. EF存储过程

    select * from Goods --创建存储过程create proc sp_Show( @index int, --当前页 @size int, --每页大小 @totalcount int ...

  2. Surface Pro (1796),安装Win11之后出现的问题。

    2020年年中我为了体验微软新的操作系统,加入了Review计划,即:Windows预览体验计划.然后升级到了Win11.由于苏菲一直是作为辅助设备用,所以平时就是开节电模式,中途也升级了几次Win1 ...

  3. 【python】绘图坐标轴标题中包含上标或下标

    plt.ylabel("流量($\mathregular{m^3}$/s)")          #绘图坐标轴添加上标$\mathregular{m^3}$,若是下标m_3 不加m ...

  4. vue后台管理系统——用户管理模块

    电商后台管理系统的功能--用户管理模块 1. 用户管理概述 通过后台管理用户的账号信息,具体包括用户信息的展示.添加.修改.删除.角色分配.账号启用/注销等功能. 用户信息列表展示 添加用户 修改用户 ...

  5. PHP、Navicat安装

    一.PHPStudy小皮面板:https://public.xp.cn/upgrades/phpStudy_64.zip 下载完成后解压后双击 点击立即安装 安装完成 启动MySQL,Nginx(my ...

  6. yield基础知识

    function* y(p1){ let r=p1; r=(yield r-5) //表达式A,在第1轮是普通return,在第2轮next(param)时会被param替换 r=(yield r*2 ...

  7. JavaScript数据类型以及转换

    一.数据类型 分类 基本(值)类型: String Number Boolean undefined unll 对象(引用)类型: Object:任意对象 Array:一种特别的对象 Function ...

  8. jmeter中使用csv文件时设置编码

    1.新建XLS文件,另存为CSV格式文件 2.在jmeter中可以尝试将编码设置成GB2312,或者utf-8

  9. Shell脚本结构化-控制流

    脚本结构化命令 上一章给出的那些 shell 脚本里,shell 按照命令在脚本中出现的顺序依次进行处理.对顺序操作来说,这已经足够了,因为在这种操作环境下,你想要的就是所有的命令按照正确的顺序执行. ...

  10. 关于IllegalMonitorStateException异常的解释之一

    注意 在同步控制方法或同步控制块里调用wait(),notify()和notifyAll().如果在非同步控制方法里调用这些方法,程序能通过编译,但运行的时候,将得到IllegalMonitorSta ...