【MySQL】如何优化SQL查询的总体框架(详细版,关于如何优化数据库服务器从大到小详细说明了步骤)

news2024/10/7 6:42:41

文章目录

  • 1 数据库服务器的优化步骤
  • 2 观察
    • 2.1 观察系统总体运行情况
    • 2.2 定位执行慢的 SQL:慢查询日志
    • 2.3 查看 SQL 执行成本:SHOW PROFILE
    • 2.4 分析查询语句:EXPLAIN(重点掌握)
      • 2.4.1 EXPLAIN各列作用
      • 2.4.2 EXPLAIN 的 type 列
      • 1.4.3 EXPLAIN 的 Extra 列
      • 1.4.4 一个优化案例
  • 2 参考资料

1 数据库服务器的优化步骤

当我们遇到数据库调优问题的时候,该如何思考呢?这里把思考的流程整理成下面这张图。整个流程划分成了 观察(Show status)行动(Action) 两个部分。字母 S 的部分代表观察(会使用相应的分析工具),字母 A 代表的部分是行动(对应分析可以采取的行动)。

小结:

2 观察

2.1 观察系统总体运行情况

在 MySQL中,可以使用 SHOW STATUS 语句查询一些数据库服务器的运行情况,如:性能参数 、 执行频率等。

备注:

1、show status 是由数据库自行维护的,作用是记录系统的运行情况,用户不可修改。

2、与 show status 类似的有一个 show variables 描述的是系统的一些系统变量,这些用户是可以控制的,用来调整系统的一些情况

SHOW STATUS语句语法如下:

SHOW [GLOBAL|SESSION] STATUS LIKE '参数';

一些常用的性能参数如下:

  • Connections:连接MySQL服务器的次数。
  • Uptime:MySQL服务器的上线时间。
  • Slow_queries:慢查询的次数
  • Innodb_rows_read:Select查询返回的行数
  • Innodb_rows_inserted:执行INSERT操作插入的行数
  • Innodb_rows_updated:执行UPDATE操作更新的行数
  • Innodb_rows_deleted:执行DELETE操作删除的行数
  • Com_select:查询操作的次数
  • Com_insert:插入操作的次数。对于批量插入的 INSERT 操作,只累加一次
  • Com_update:更新操作的次数。
  • Com_delete:删除操作的次数。

举例:

show status like 'Uptime';

2.2 定位执行慢的 SQL:慢查询日志

关于慢日志,作者写了另外的文章,这里不做过多介绍,《5.4.5 The Slow Query Log(慢日志实验).md》

2.3 查看 SQL 执行成本:SHOW PROFILE

show profile 的作用是查看sql消耗的资源,也就是通常所说的成本。

show variables like 'profiling';

通过设置 profiling='ON' 来开启 show profile:

set profiling = 'ON';

然后执行相关的查询语句。接着看下当前会话都有哪些 profiles,使用下面这条命令:

show profiles;

你能看到当前会话一共有 2 个查询。查看某一次查询的资源使用情况使用:

show profile cpu,block io for query 2;

show profile 在新的版本中标注过期了,官方建议大家使用性能库,即 performance_schema

2.4 分析查询语句:EXPLAIN(重点掌握)

使用语法:

EXPLAIN SELECT select_options

如果我们想看看某个查询的执行计划的话,可以在具体的查询语句前边加一个 EXPLAIN ,就像这样:

EXPLAIN SELECT 1;

EXPLAIN 语句输出的各个列的作用如下:

列名描述
id在一个大的查询语句中每个SELECT关键字都对应一个 唯一的id
select_type SELECT关键字对应的那个查询的类型
table表名
partitions匹配的分区信息
type针对单表的访问方法
possible_keys可能用到的索引
key实际上使用的索引
key_len实际使用到的索引长度
ref 当使用索引列等值查询时,与索引列进行等值匹配的对象信息
rows预估的需要读取的记录条数
filtered某个表经过搜索条件过滤后剩余记录条数的百分比
Extra一些额外的信息

2.4.1 EXPLAIN各列作用

为了让大家有比较好的体验,我们调整了下 EXPLAIN 输出列的顺序。

1. table:

不论我们的查询语句有多复杂,里边儿 包含了多少个表 ,到最后也是需要对每个表进行 单表访问 的,所以MySQL规定EXPLAIN语句输出的每条记录都对应着某个单表的访问方法,该条记录的table列代表着该表的表名(有时不是真实的表名字,可能是简称)。

2. id:

我们写的查询语句一般都以 SELECT 关键字开头,比较简单的查询语句里只有一个 SELECT 关键字,id就可以理解为一个select语句。

  • id如果相同,可以认为是一组,从上往下顺序执行
  • 在所有组中,id值越大,优先级越高,越先执行
  • 关注点:id号每个号码,表示一趟独立的查询, 一个sql的查询趟数越少越好

3. select_type:

查询类型。有如下表:

名称描述
SIMPLESimple SELECT (not using UNION or subqueries)(只要不是union和子查询)
PRIMARYOutermost SELECT(最外面的查询)
UNIONSecond or later SELECT statement in a UNION(union)
DEPENDENT UNIONSecond or later SELECT statement in a UNION, dependent on outer query(union且依赖外部查询)
UNION RESULTResult of a UNION.( union之后的结果)
SUBQUERYFirst SELECT in subquery(子查询)
DEPENDENT SUBQUERYFirst SELECT in subquery, dependent on outer query(子查询且依赖外部查询)
DERIVEDDerived table(派生表)
DEPENDENT DERIVEDDerived table dependent on another table(派生表且依赖其他表)
MATERIALIZEDMaterialized subquery(物化子查询)
UNCACHEABLE SUBQUERYA subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query

具体分析如下:

  • SIMPLE

    除了子查询和UNION都是simple

    EXPLAIN SELECT * FROM s1;
    

    当然,连接查询也算是 SIMPLE 类型,比如:

    EXPLAIN SELECT * FROM s1 INNER JOIN s2;
    

  • PRIMARY

    EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;
    

  • UNION

  • UNION RESULT

  • SUBQUERY

    EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';
    

  • DEPENDENT SUBQUERY

    EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE s1.key2 = s2.key2) OR key3 = 'a';
    

  • DEPENDENT UNION

    EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE key1 = 'a' UNION SELECT key1 FROM s1 WHERE key1 = 'b');
    

  • DERIVED

    EXPLAIN SELECT * FROM (SELECT key1, count(*) as c FROM s1 GROUP BY key1) AS derived_s1 where c > 1;
    

  • MATERIALIZED

    EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2);
    

  • UNCACHEABLE SUBQUERY

  • UNCACHEABLE UNION

2.4.2 EXPLAIN 的 type 列

针对上文提到的type类型,这里重点说明。

EXPLAIN输出的type列描述了如何联接表。以下列表描述了连接类型,按从最佳类型到最差类型的顺序排列:

  • system

    只有一行数据的表,是const的一种特殊情况

    CREATE TABLE t(i int) Engine=MyISAM;
    INSERT INTO t VALUES(1);
    EXPLAIN SELECT * FROM t;
    
  • const

    常量级别,表中最多只匹配一行且在查询开始的时候就被读取到了。这种情况就是 PRIMARY KEYUNIQUE。举例:

    SELECT * FROM tbl_name WHERE primary_key=1;
    -- 右边是常量,左边是主键
    SELECT * FROM tbl_name
      WHERE primary_key_part1=1 AND primary_key_part2=2;
    
  • eq_ref

    等值引用。从当前的表读取一行与先前的表匹配。这是除了system、const以外最快的方式,如在 PRIMARY KYEUNIQUE NOT NULL 会使用。举例如下:

    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column=other_table.column;
    
    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column_part1=other_table.column
      AND ref_table.key_column_part2=1;
    
  • ref

    引用,跟 eq_ref 不同的是ref可能会匹配多行而eq_ref匹配一行。对于前一个表中的每一个行组合,都会从此表中读取具有匹配索引值的所有行。当键不是PRIMARY key或UNIQUE索引(换句话说,如果联接不能根据键值选择一行),则使用ref。举例:

    -- 不是 primary key 或者 unique
    SELECT * FROM ref_table WHERE key_column=expr;
    
    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column=other_table.column;
    
    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column_part1=other_table.column
      AND ref_table.key_column_part2=1;
    
  • fulltext

  • ref_or_null

    这个join type类型跟ref类似,但是可能会包括null。举例:

    SELECT * FROM ref_table
      WHERE key_column=expr OR key_column IS NULL;
    
  • index_merge

    此联接类型表示使用了索引合并优化。在查询的列都来自索引时可能会发生。

  • unique_subquery

    用来在子查询中代替 eq_ref。举例:

    -- primary_key 是唯一索引
    value IN (SELECT primary_key FROM single_table WHERE some_expr)
    
  • index_subquery

    跟 unique_subquery类似。它代替 IN 子查询,但是它和非唯一索引一起工作。举例:

    -- key_column 是非唯一索引
    value IN (SELECT key_column FROM single_table WHERE some_expr)
    
  • range

    范围。使用索引选择给定范围的行的类型就是range。通常在这些情况发生:=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN、LIKE、IN()。举例:

    SELECT * FROM tbl_name
      WHERE key_column = 10;
    
    SELECT * FROM tbl_name
      WHERE key_column BETWEEN 10 and 20;
    
    SELECT * FROM tbl_name
      WHERE key_column IN (10,20,30);
    
    SELECT * FROM tbl_name
      WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
    
  • index

    当覆盖索引时一般使用index,该类型跟all差不多效率除了特殊情况外。

  • all

    全表扫描

1.4.3 EXPLAIN 的 Extra 列

EXPLAIN输出的Extra列包含有关MySQL如何解析查询的附加信息。以下列表说明了可以在此列中显示的值。以下列举几个常见的

  • Backward index scan

    反向索引扫描

  • const row not found

  • Distinct

  • Full scan on NULL key

  • Impossible HAVING

    不可能的having条件

  • Impossible WHERE

    不可能的where条件

  • No tables used

  • unique row not found

  • Using filesort

  • Using index

    只使用索引树中的信息从表中检索列信息,而不必进行额外的查找来读取实际行。当查询仅使用作为单个索引一部分的列时,可以使用此策略。

  • Using temporary

    为了解决查询,MySQL需要创建一个临时表来保存结果。通常发生在GROUP BY和ORDER BY子句

  • Using where

1.4.4 一个优化案例

有如下的sql语句

EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
               tt.ProjectReference, tt.EstimatedShipDate,
               tt.ActualShipDate, tt.ClientID,
               tt.ServiceCodes, tt.RepetitiveID,
               tt.CurrentProcess, tt.CurrentDPPerson,
               tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
               et_1.COUNTRY, do.CUSTNAME
        FROM tt, et, et AS et_1, do
        WHERE tt.SubmitTime IS NULL
          AND tt.ActualPC = et.EMPLOYID
          AND tt.AssignedPC = et_1.EMPLOYID
          AND tt.ClientID = do.CUSTNMBR;

被比较的列如下:

TableColumnData Type
ttActualPCCHAR(10)
ttAssignedPCCHAR(10)
ttClientIDCHAR(10)
etEMPLOYIDCHAR(15)
doCUSTNMBRCHAR(15)

表的索引如下:

TableColumnData Type
ttActualPCCHAR(10)
ttAssignedPCCHAR(10)
ttClientIDCHAR(10)
etEMPLOYIDCHAR(15)
doCUSTNMBRCHAR(15)

现在用explain分析出来的结果如下:

table type possible_keys key  key_len ref  rows  Extra
et    ALL  PRIMARY       NULL NULL    NULL 74
do    ALL  PRIMARY       NULL NULL    NULL 2135
et_1  ALL  PRIMARY       NULL NULL    NULL 74
tt    ALL  AssignedPC,   NULL NULL    NULL 3872
           ClientID,
           ActualPC
      Range checked for each record (index map: 0x23)

现在应该如何优化?

分析:

1、从执行计划的输出可以看到所有的链接类型都是ALL,这是全表扫描非常地效;从rows列的乘积 74 * 2135 * 74 * 3872 的结果可以看出需要扫描的行的数量将非常多(即使结果只有很少一部分);但是可以看到对表却是建立了索引,那为啥索引没有被使用到?

2、仔细观察发现是因为字段的类型长度不一样,有 char(10) 和 char(15),很明显只能扩长度不能缩小长度。执行如下操作重新观察执行计划

ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),MODIFY ClientID   VARCHAR(15);
table type   possible_keys key      key_len ref           rows Extra
et    ALL    PRIMARY       NULL     NULL    NULL          74
tt    ref    AssignedPC,   ActualPC 15      et.EMPLOYID   52   Using
             ClientID,                                         where
             ActualPC
et_1  eq_ref PRIMARY       PRIMARY  15      tt.AssignedPC 1
do    eq_ref PRIMARY       PRIMARY  15      tt.ClientID   1

达到这一步基本已经很完美了,索引基本上都使用到了,而且是eq_ref和ref效率都还可以。

3、但是仔细分析发现

  • 在 Extra 列使用过滤条件的列(即第二列)并没有作为驱动表,驱动表是et表(第一行是驱动表)。

  • 优化器预估tt扫描52行,et扫描74行,既然tt表扫描的行少,那应该让tt表作为驱动表

4、执行以下语句让MySQL分析关键字的分布情况(在Oracle中也叫做收集统计信息)

ANALYZE TABLE tt;

5、重新查看执行计划,如下:

table type   possible_keys key     key_len ref           rows Extra
tt    ALL    AssignedPC    NULL    NULL    NULL          3872 Using
             ClientID,                                        where
             ActualPC
et    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC   1
et_1  eq_ref PRIMARY       PRIMARY 15      tt.AssignedPC 1
do    eq_ref PRIMARY       PRIMARY 15      tt.ClientID   1

2 参考资料

官网:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

show status:参考我的文章:《13.7.7.37 SHOW STATUS Statement.md》

理解执行计划:参考我的文章:《8.8.2 EXPLAIN Output Format(explain 输出执行计划的格式).md》

书籍:《InnoDB 存储引擎》,该书电子版书籍作者无套路免费下载


传送门: 保姆式Spring5源码解析

欢迎与作者一起交流技术和工作生活

联系作者


传送门: 保姆式Spring5源码解析

欢迎与作者一起交流技术和工作生活

联系作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/743903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

银行安全用电监管平台可行性研究及解决方案

2017年4月26日&#xff0c;国务院安全生产委员会印发《国务院安全生产委员会关于开展电气火灾综合治理工作的通知》&#xff08;安委〔2017〕4号&#xff09;&#xff0c;强调用三年时间综合治理电气火灾工作&#xff0c;提高社会单位发现和处置消防电气安全隐患能力&#xff0…

2023国自然会评:上会及分数解析,这几种情况本子容易被拿下?

国自然基金上会标准 今年的会评已经临近“重头戏”---面青地项目会议评审。 在国自然会评中&#xff0c;通过函评筛选出的科研工作者&#xff0c;经过会评筛选和评审&#xff0c;最终被评选出的项目将获得国自然会的资金支持。 国自然的会评&#xff0c;分为几个部分&#x…

美国访问学者怎么考驾照?

作为一个美国访问学者&#xff0c;你可能会想知道在美国如何考取驾照。在这篇文章中&#xff0c;知识人网小编将介绍美国的驾照考试流程和一些相关要求。 首先&#xff0c;作为一名访问学者&#xff0c;你需要了解美国各州对驾照的规定可能会有所不同。因此&#xff0c;在考取驾…

单片机尽力少用位域操作

1、在51单片机中少用uint32_t类型&#xff0c;查看汇编真的好多条指令&#xff0c;尽力避免少用。 2、在32位单片机中&#xff0c;u8、u16、u32类型操作起来基本没有什么影响&#xff0c;下图是我做的测试&#xff0c;可能测试不全面&#xff0c;按照当前测试&#xff0c;在32…

CVE-2023-28432-MinIO集群模式信息泄露漏洞流量分析

简介 MinIO是一个开源对象存储系统。 在其RELEASE.2023-03-20T20-16-18Z版本&#xff08;不含&#xff09;以前&#xff0c;集群模式部署下存在一处信息泄露漏洞&#xff0c;攻击者可以通过发送一个POST数据包获取进程所有的环境变量&#xff0c;其中就包含账号密码MINIO_SEC…

ElasticSearch8.7 搭配 SpringDataElasticSearch5.1 的使用

0. 前言 终于&#xff01;终于&#xff01;自个翻遍了网上的文章&#xff0c;加上对官网的文档和API的翻找&#xff0c;终于明白这玩意到底更新出了个啥出来&#xff01; 本文章会带你了解&#xff0c;使用 SpringDataES5.1 对 ES8.7 的【新增、修改、删除、多条件查询、聚合】…

MFC 工具栏中的按钮控件下拉式

有一个需求 工具栏中的按钮需要有一个下拉按钮&#xff0c;点击下拉按钮可以弹出一个子窗口来选择 显示该 TBSTYLE_EX_DRAWDDARROWS 扩展的样式设置&#xff0c;将箭头下方将显示。 DWORD dwExStyle TBSTYLE_EX_DRAWDDARROWS; m_toolbar.GetToolBarCtrl().SendMessage(TB_SE…

「深度学习之优化算法」(十一)鲸鱼算法

1. 鲸鱼算法简介 (以下描述,均不是学术用语,仅供大家快乐的阅读)   鲸鱼算法(Whale Optimization Algorithm)是根据鲸鱼围捕猎物的行为而提出的算法。鲸鱼是一种群居的哺乳动物,在捕猎时它们也会相互合作对猎物进行驱赶和围捕。鲸鱼算法提出时间并不长,也是一个新兴…

利用Gradio的UploadButton模块实现文件上传功能

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

requestAnimationFrame性能测试

requestAnimationFrame&#xff1a;每次重绘最多只调用一次回调函数 测试开启/关闭requestAnimationFrame的监听事件调用次数差异&#xff1a; 先说结论&#xff1a;存在约8倍的调用次数差距&#xff01; requestAnimationFrame使用与否的次数差距 本次测试代码为drag事件 c…

Pycharm设置Python文件页眉默认信息(作者姓名、创建时间等)

次点击File->Settings->Editor->File and Code Templates->然后选择Python script. 后将下列代码复制到右边的框框中&#xff0c;然后选择apply应用&#xff0c;就可以啦 ##!/usr/bin/python3 # -*- coding: utf-8 -*- # Time : ${DATE} ${TIME} # Author : 作者…

【CSS加载动画特效】28种纯CSS实现的加载loading动态特效(附源码)

文章目录 写在前面涉及知识点效果展示1、Loading节点的创建2、部分效果的实现源码1&#xff09;三点加载动画Html代码CSS样式代码 2&#xff09;圆点矩阵加载特效Html代码CSS样式代码 3&#xff09;圆形轨迹加载动画Html代码Css样式代码 4&#xff09;栅栏式加载动画Html代码Cs…

Qt/C++音视频开发46-音视频同步保存到MP4

一、前言 用ffmpeg单独做视频保存不难&#xff0c;单独做音频保存也不难&#xff0c;难的是音视频同步保存到MP4中&#xff0c;重点是音视频要同步&#xff0c;其实这也不难&#xff0c;只要播放那边音视频同步后的数据&#xff0c;写入到文件即可。最难的是在播放过程中不断随…

python对dataframe索引的操作

目录 假如有个dataframe如下&#xff0c;这里需要去除第一个aa&#xff0c;保留最后一个aa 关键代码 # 如果你想保留第一个aa&#xff0c;那么keep就是first df.reset_index().drop_duplicates(subsetindex, keepfirst).set_index(index)结果如下&#xff1a; 原文链接&am…

10.1.5 查询指令是否为 Bash shell 的内置命令: type

通过 type 这个指令我们可以知道每个指令是否为 bash 的内置指令。 此外&#xff0c;由于利用 type 搜寻后面的名称时&#xff0c;如果后面接的名称并不能以可执行文件的状态被找到&#xff0c; 那么该名称是不会被显示出来的。也就是说&#xff0c; type 主要在找出“可执行文…

3 Prometheus安装

目录 1. 安装Prometheus 2. 基于linux安装Prometheus 下载安装包 将安装包放在合适的目录下 启动prometheus 访问 3. 配置Prometheus 3.1 global 3.2 alerting 3.3 rule_files 3.4 static_configs 4. 第一个指标 5 表达式浏览器 指标列表自动填充 指标名称筛选 指…

pytorch的whl文件安装

下载.whl文件&#xff0c;离线安装 提示&#xff1a;下载torch的稳定版本网址[https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html) 首先&#xff0c;查看主机显卡和安装的cuda版本。 可以在命令行输入:nvcc -V 如果…

使用jquery遇到的问题Unresolved function or method $()

今天在使用jquery的时候&#xff0c;发现页面中即使引入了jquery.min.js&#xff0c;js代码中仍然说找不到$()&#xff0c;原来的项目也是用的jquery.min.js&#xff0c;为什么之前的就没有这个问题呢。 然后利用搜索引擎查了一下解决方案&#xff0c;最后还是决定改成未压缩版…

触摸按键控制LED灯亮灭

文章目录 前言一、触摸按键介绍二、触摸按键电路原理模式一&#xff1a;模式二&#xff1a; 三、系统设计1、模块框图2、RTL视图 四、源码1、touch_led模块 五、效果六、总结七、参考资料 前言 环境&#xff1a; 1、Quartus18.1 2、vscode 3、板子型号&#xff1a;原子哥开拓者…

前端熟练发起ajax请求的多种方法

1.原生发起ajax 1.1概念&#xff1a; 说明&#xff1a;XMLHttpRequest是 JavaScript 的内置对象&#xff0c;用于在Web应用程序中向服务器发送HTTP请求和接收响应。通过XMLHttpRequest对象&#xff0c;可以实现异步加载数据&#xff0c;无需刷新整个页面即可更新部分内容。常…