文章目录

  • 1.1 SQL的性能分析
    • 1.1.1 通过 show status 命令了解各种 SQL 的执行频率
    • 1.1.2 慢查询日志
    • 1.1.3 profile分析
    • 1.1.4 通过 EXPLAIN 分析低效 SQL 的执行计划
  • 1.2 常用的SQL语句优化

1.1 SQL的性能分析

  当面对一个有 SQL 性能问题的数据库时,我们应该首先进行系统的分析,使得能够尽快定位问题 ,并通过优化SQL 从而解决问题。

1.1.1 通过 show status 命令了解各种 SQL 的执行频率

  MySQL 客户端连接成功后,通过 show [session|global]status 命令可以提供服务器状态信息。show [session|global] status 可以根据需要加上参数“session”或者“global”来显示 session 级(当前连接)的统计结果和 global 级(自数据库上次启动至今)的统计结果。如果不写,默认使用参数是“session”。

show status like 'Com_%';

Com_xxx 表示执行xxx操作,Value表示每个 xxx 语句执行的次数,通常比较关心的是以下几个统计参数。

  • Com_select:执行 SELECT 操作的次数,一次查询只累加 1。
  • Com_insert:执行 INSERT 操作的次数,对于批量插入的 INSERT 操作,只累加一次。
  • Com_update:执行 UPDATE 操作的次数。
  • Com_delete:执行 DELETE 操作的次数。

  通过以上几个参数,可以很容易地了解当前数据库的应用是以插入更新为主还是以查询操作为主,以及各种类型的 SQL 大致的执行比例是多少。对于更新操作的计数,是对执行次数的计数,不论提交还是回滚都会进行累加。

  对于事务型的应用,通过 Com_commit 和 Com_rollback 可以了解事务提交和回滚的情况,对于回滚操作非常频繁的数据库,可能意味着应用编写存在问题。

此外,以下几个参数便于用户了解数据库的基本情况。

  • Connections:试图连接 MySQL 服务器的次数。
  • Uptime:服务器工作时间。
  • Slow_queries:慢查询的次数。

1.1.2 慢查询日志

  通过慢查询日志定位那些执行效率较低的 SQL 语句。慢查询日志会记录超出自己设置的时间还没有执行完毕的sql。默认情况下,MySQL数据库并不启动慢查询日志,需要我们手动来设置这个参数,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件,也支持将日志记录写入数据库表。

SHOW VARIABLES LIKE '%slow_query_log%';

默认情况下slow_query_log的值为OFF,表示慢查询日志是禁用的,可以通过设置slow_query_log的值来开启。

开启慢查询日志sql:

SET GLOBAL slow_query_log=1;

设置慢查询的超时时间(以秒为单位):

SET GLOBAL long_query_time=2;

使用set global slow_query_log=1开启了慢查询日志只对当前数据库生效,MySQL重启后则会失效。如果要永久生效,就必须修改配置文件my.cnf。

1.1.3 profile分析

  1. 查看profile是否可用:
SELECT @@profiling;

  1. 开启profile:
SET profiling = 1;
  1. 查看当前会话下的所有sql执行时间:
SHOW PROFILES;

  1. 查看具体sql的每个步骤消耗时间:
SHOW PROFILE FOR QUERY xx;  -- xx是上图的query_id

  1. 查看具体sql的cpu消耗时间:
SHOW PROFILE cpu FOR QUERY xx;  -- xx是query_id

1.1.4 通过 EXPLAIN 分析低效 SQL 的执行计划

explain是非常重要的关键字,通过explain我们可以获得以下信息:

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

使用方法:explain + SQL语句,例如:

explain select * from user where id = 100030011

  1. id字段

id可以认为是查询序列号,每一个id代表一个select,一句sql有两个select,就会有两行数据,两个id,不同的id代表不同的子查询。

  • id相同执行顺序由上至下。
  • id不同,id值越大优先级越高,越先被执行。
  • id为NULL最后执行。
  1. select_type:表示查询的类型

常见的类型有:

select_type description
SIMPLE 简单表,即不使用表连接或者子查询
PRIMARY 包含子查询时,外层查询就显示为 PRIMARY
UNION UNION 中的第二个或者后面的查询语句
SUBQUERY 子查询中的第一个 SELECT
  1. table:输出结果集的表

显示这一行的数据是关于哪张表的,有时不是真实的表名字,也可能是表的别名。

  1. type:表示表的连接类型

性能由好到差的连接类型为:system、const、eq_ref、ref、ref_or_null、index_merge、unique_subquery、index_subquery、range、index、all等。

type description
system 表中仅有一行,即常量表
const 单表中最多有一个匹配行,例如 primary key 或者 unique index
eq_ref 对于前面的每一行,在此表中只查询一条记录,简单来说,就是多表连接中使用 primary key或者 unique index
ref 与 eq_ref 类似,区别在于不是使用 primary key 或者 unique index,而是使用普通的索引
ref_or_null 与 ref 类似,区别在于条件中包含对 NULL 的查询
index_merge 索引合并优化
unique_subquery in 的后面是一个查询主键字段的子查询
index_subquery 与 unique_subquery 类似,区别在于 in 的后面是查询非唯一索引字段的子查询
range 单表中的范围查询
index 对于前面的每一行,都通过查询索引来得到数据
all 对于前面的每一行,都通过全表扫描来得到数据
  1. possible_keys:表示查询时,可能使用的索引。
  2. key:表示实际使用的索引。
  3. key_len:索引字段的长度。
  4. rows:扫描行的数量。
  5. Extra:执行情况的说明和描述。

1.2 常用的SQL语句优化

  1. 不要使用 SELECT *, 必须使用 SELECT <字段列表> 查询。查找哪个字段,就写具体的字段。例如:
select name, age from user where address = 123;

原因:

  • 消耗更多的 CPU 和 IO 以网络带宽资源
  • 无法使用和覆盖索引
  • 可减少表结构变更带来的影响
  1. 不要使用不含字段列表的 INSERT 语句,例如:
-- 不使用:
insert into t values ('a','b','c');
-- 应该使用:
insert into t(c1,c2,c3) values ('a','b','c');
  1. 避免使用子查询,可以把子查询优化为 join 操作。

子查询性能差的原因:

  子查询的结果集无法使用索引,通常子查询的结果集会被存储到临时表中,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。特别是对于返回结果集比较大的子查询,其对查询性能的影响也就越大。由于子查询会产生大量的临时表也没有索引,所以会消耗过多的 CPU 和 IO 资源,产生大量的慢查询。

  1. 避免使用 JOIN 关联太多的表。
  • 对于 MySQL 来说,是存在关联缓存的,缓存的大小可以由 join_buffer_size 参数进行设置。

  • 在 MySQL 中,对于同一个 SQL 多关联(join)一个表,就会多分配一个关联缓存,如果在一个 SQL 中关联的表越多,所占用的内存也就越大。

  • 如果程序中大量的使用了多表关联的操作,同时 join_buffer_size 设置的也不合理的情况下,就容易造成服务器内存溢出的情况,就会影响到服务器数据库性能的稳定性。

  • 同时对于关联操作来说,会产生临时表操作,影响查询效率,MySQL 最多允许关联 61 张表,建议不超过 5 个。

  1. 减少同数据库的交互次数。
  • 数据库更适合处理批量操作,合并多个相同的操作到一起,可以提高处理效率。
  1. 禁止使用 order by rand() 进行随机排序。
  • order by rand() 会把表中所有符合条件的数据装载到内存中,然后在内存中对所有数据根据随机生成的值进行排序,并且可能会对每一行都生成一个随机值,如果满足条件的数据集非常大,就会消耗大量的 CPU 和 IO 及内存资源。

  • 推荐在程序中获取一个随机值,然后从数据库中获取数据的方式。

  1. WHERE 从句中禁止对列进行函数转换和计算。
  • 对列进行函数转换或计算时,会导致引擎放弃使用索引而进行全表扫描。

  • 这样的查询也会导致全表扫描:select id from student where name like '%李%',可以考虑使用全文索引。

  1. 在明显不会有重复值时使用 UNION ALL 而不是 UNION。
  • UNION 会把两个结果集的所有数据放到临时表中后再进行去重操作
  • UNION ALL 不会再对结果集进行去重操作
  1. 拆分复杂的大 SQL 为多个小 SQL。
  • 大 SQL 逻辑上比较复杂,需要占用大量 CPU 进行计算
  • MySQL 中,一个 SQL 只能使用一个 CPU 进行计算
  • SQL 拆分后可以通过并行执行来提高处理效率

有哪些SQL优化的手段?相关推荐

  1. 互联网中慢SQL优化手段

    一个再完美的架构,也会因为一个慢SQL导致系统直接崩溃. 最近在做一个比较有意思的工作,优化系统中的慢SQL,整个过程我是很享受的,往往很多慢SQL都是系统中调用非常频繁的接口,这让我对业务更加熟悉, ...

  2. 大牛是怎么思考设计SQL优化方案的?

    作者:惨绿少年 https://www.cnblogs.com/clsn/p/8214048.html 在进行MySQL的优化之前,必须要了解的就是MySQL的查询过程,很多查询优化工作实际上就是遵循 ...

  3. MySQL SQL优化

    前言 有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧. 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础. 优化目标 ...

  4. mysql sql优化_浅谈mysql中sql优化

    说到sql优化,一般有几个步骤呢,在网上看到了一篇很不错的帖子.在这分享一下吧,也是自己学习的一个过程. 一.查找慢查询 1.1.查看SQL执行频率 SHOW STATUS LIKE 'Com_%'; ...

  5. MySQL数据库性能优化--SQL优化

    有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧. 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础 优化目标 减少 I ...

  6. 关于数据库SQL优化

    1.数据库访问优化 要正确的优化SQL,我们需要快速定位能性的瓶颈点,也就是说快速找到我们SQL主要的开销在哪里?而大多数情况性能最慢的设备会是瓶颈点,如下载时网络速度可能会是瓶颈点,本地复制文件时硬 ...

  7. 史上最全SQL优化方案

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 作者 ...

  8. sql优化的方法及思路_合理的sql优化思路--如何缩短SQL调优时间?

    概述 当生产环境发生故障或者系统特别慢的时候,这时候你从awr报告拿到有问题的sql,但是优化的时候却优化了很久还没解决,这时候在领导或者客户面前就不太好了...那么我们怎么去缩短sql调优的时间,一 ...

  9. 52条实用经验,SQL优化不再难!

    " 不论是面试还是实际开发(后端),SQL 优化一直是绕不开的一个话题,本文会提到 52 条 SQL 语句性能优化策略. 图片来自 Pexels 有些优化策略需要你有一定的 SQL 实践才能 ...

最新文章

  1. python编码规范手册-python编码规范
  2. Redis-序列化和存储模式
  3. 2021年全新各方向IT职业技能图谱
  4. Linux 下面的时区与时间错误修复过程记载(血泪篇)
  5. 顶级程序员的心得 Coders at Work (I)
  6. java 弹出软键盘_Android开发之弹出软键盘工具类简单示例
  7. python 函数内部声明全局变量
  8. namedtuple可命名元组
  9. 广度优先搜索生成树怎么画_LeetCode0938: 二叉搜索树的范围和
  10. myeclipse从svn检出代码转成maven后格式有误解决方法
  11. python标准库:collections和heapq模块
  12. 天正建筑8.5 天正给排水8.5天正电气8.5天正暖通8.5及注册机(32位)
  13. Andriod --- JetPack :LiveData setValue 和 postValue 的区别
  14. android mac地址不可用,Android手机里的mac地址显示不可用是为什么。我的手机是海信E920....
  15. 如何使用纯 CSS(border-radius 和 clip)属性画出半圆
  16. 摸个鱼的功夫,搞懂双亲委派机制
  17. Windows10应用程序无法正常启动Oxc000007b 实用解决方法
  18. 科学计算机复利现值怎么计算公式,复利现值计算公式
  19. 啊哈添柴挑战Java1221. 输出三角形
  20. 【论文写作——投稿和审稿】

热门文章

  1. Selenium自动化爬取某东商品信息
  2. CN2线路香港服务器和BGP线路比较
  3. CSS 超过三行显示...
  4. 09 JVM架构模型
  5. 分数换算小数补0法_计算机存储整数和小数
  6. linuxcnc 源码解读01
  7. BorderLayout小练习
  8. RV1126 适配 Debian10(搭建人脸识别云服务器)
  9. 【Windows 10】我们无法设置移动热点
  10. SQLyog 链接MYSQL 8.0错误代码1251