1.概述

在应用系统开发过程中,由于初期数据量小,开发人员写SQL语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多SQL语句开始逐渐显露出性能问题,对生产环境的影响也越来越大,此时这些有问题的SQL语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化,该章节将详细介绍在MySQL中优化SQL语句的方法。

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

MySQL客户端连接成功后,通过show [session|global]status命令可以提供服务器状态信息,也可以在操作系统上使用mysqladmin extended-status命令获得这些消息。show [session|global] status可以根据需要加上参数“session”或者“global”来显示session级(当前连接)的统计结果和global级(自数据库上次启动至今)的统计结果。如果不写,默认使用参数是“session”。
下面的命令显示了当前session中所有统计参数的值:

-- 查看会话所有统计的值
SHOW STATUS LIKE 'Com_%';
Or
SHOW SESSION STATUS LIKE 'Com_%';

下面的命令显示了当前global中所有统计参数的值:
-- 查看全局所有统计的值

SHOW GLOBAL STATUS LIKE 'Com_%';


Com_xxx表示每个xxx语句执行的次数,我们通常比较关心的是以下几个统计参数:
●Com_select:执行SELECT操作的次数,一次查询只累加1。
●Com_insert:执行INSERT操作的次数,对于批量插入的INSERT操作,只累加一次。
●Com_update:执行UPDATE操作的次数。
●Com_delete:执行DELETE操作的次数。
上面这些参数对于所有存储引擎的表操作都会进行累计。下面这几个参数只是针对InnoDB存储引擎的,累加的算法也略有不同。
●Innodb_rows_read:SELECT查询返回的行数。
●Innodb_rows_inserted:执行INSERT操作插入的行数。
●Innodb_rows_updated:执行UPDATE操作更新的行数。
●Innodb_rows_deleted:执行DELETE操作删除的行数。
通过以上几个参数,可以很容易地了解当前数据库的应用系统是以插入更新为主还是以查询操作为主,以及各种类型的SQL大致的执行比例是多少。对于更新操作的计数,是对执行次数的计数,不论提交还是回滚都会进行累加。
对于事务型的应用,通过Com_commit和Com_rollback可以了解事务提交和回滚的情况,对于回滚操作非常频繁的数据库,可能意味着应用编写存在问题。此外,以下几个参数便于用户了解数据库的基本情况。 
●Connections:试图连接MySQL服务器的次数。
●Uptime:服务器工作时间。
●Slow_queries:慢查询的次数。

3.定位执行效率较低的SQL语句

可以通过以下两种方式定位执行效率较低的SQL语句。
通过慢查询日志定位那些执行效率较低的SQL语句,用--log-slow-queries[=file_name]选项启动时,mysqld写一个包含所有执行时间超过long_query_time秒的SQL语句的日志文件。
慢查询日志在查询结束以后才纪录,所以在应用系统反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看SQL的执行情况,同时对一些锁表操作进行优化。

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

通过定位执行效率较低的SQL语句后,可以通过EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序,比如想统计所有库存阶梯数量,需要关联goods_stock表和goods_stock_price表,并且对goods_stock_price.Qty字段做求和(sum)操作,相应 SQL 的执行计划如下:

EXPLAIN SELECT SUM(sp.Qty)
FROM goods_stock AS s LEFT JOIN goods_stock_price AS sp
ON s.ID=sp.GoodsStockID;


如上图所示每个列的简单解释如下:
●select_type:表示 SELECT 的类型,常见的取值有
◎SIMPLE(简单表,即不使用表连接 或者子查询)、
◎PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或 者后面的查询语句)、◎SUBQUERY(子查询中的第一个SELECT)等。 
●table:输出结果集的表。
●type:表示表的连接类型,性能由好到差的连接类型为:
◎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(对于前面的每一行,都通过全表扫描来得到数据)。
●possible_keys:表示查询时,可能使用的索引。
●key:表示实际使用的索引。
●key_len:索引字段的长度。
●rows:扫描行的数量。
●Extra:执行情况的说明和描述。

5.确定问题并采取相应的优化措施

经过以上定位步骤,我们基本就可以分析到问题出现的原因。此时我们可以根据情况采取相应的改进措施,进行优化提高语句执行效率。
在上面的例子中,已经可以确认是goods_stock是走主键索引的,但是对goods_stock_price子表的进行了全表扫描导致效率的不理想,那么应该对goods_stock_price表的GoodsStockID字段创建索引,具体命令如下:

CREATE INDEX idx_stock_price_1 ON goods_stock_price (GoodsStockID);

创建索引后,我们再看一下这条语句的执行计划,具体如下:

EXPLAIN SELECT SUM(sp.Qty)
FROM goods_stock AS s LEFT JOIN goods_stock_price AS sp
ON s.ID=sp.GoodsStockID;


可以发现建立索引后对goods_stock_price子表需要扫描的行数明显减少(从 3 行减少到1行),可见索引的使用可以大大提高数据库的访问速度,尤其在表很庞大的时候这种优势更为明显。

参考文献:
深入浅出MySQL大全

(2)MySQL进阶篇SQL优化(show status、explain分析)的更多相关文章

  1. (6)MySQL进阶篇SQL优化(MyISAM表锁)

    1.MySQL锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源 (如 CPU.RAM.I/O 等)的抢占以外,数据也是一种供许多用户共享的资源.如何保证数 据并 ...

  2. (4)MySQL进阶篇SQL优化(常用SQL的优化)

    1.概述 前面我们介绍了MySQL中怎么样通过索引来优化查询.日常开发中,除了使用查询外,我们还会使用一些其他的常用SQL,比如 INSERT.GROUP BY等.对于这些SQL语句,我们该怎么样进行 ...

  3. (3)MySQL进阶篇SQL优化(索引)

    1.索引问题 索引是数据库优化中最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数 的SQL性能问题.本章节将对MySQL中的索引的分类.存储.使用方法做详细的介绍. 2.索引的存储分类 ...

  4. (11)MySQL进阶篇SQL优化(InnoDB锁问题排查与解决)

    1.概述 前面章节之所以介绍那么多锁的知识点和示例,其实最终目的就是为了排查与解决死锁的问题,下面我们把之前学过锁知识重温与补充一遍,然后再通过例子演示下如果排查与解决死锁. 2.前期准备 ●数据库事 ...

  5. (5)MySQL进阶篇SQL优化(优化数据库对象)

    1.概述 在数据库设计过程中,用户可能会经常遇到这种问题:是否应该把所有表都按照第三范式来设计?表里面的字段到底改设置为多大长度合适?这些问题虽然很小,但是如果设计不当则可能会给将来的应用带来很多的性 ...

  6. (7)MySQL进阶篇SQL优化(InnoDB锁-事务隔离级别 )

    1.概述 在我们在学习InnoDB锁知识点之前,我觉得有必要让大家了解它的背景知识,因为这样才能让我们更系统地学习好它.InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION ...

  7. (8)MySQL进阶篇SQL优化(InnoDB锁-共享锁、排他锁与意向锁)

    1.锁的分类 锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制.之前MyISAM锁章节已经讲过锁分类,而InnoDB锁按照粒度分为锁定整个表的表级锁(table-level l ...

  8. (9)MySQL进阶篇SQL优化(InnoDB锁-记录锁)

    1.概述 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点意味着:只有通过索引条件检索 ...

  9. (10)MySQL进阶篇SQL优化(InnoDB锁-间隙锁)

    1.概述 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁:对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)&quo ...

随机推荐

  1. HDU - 4722 Good Numbers 【找规律 or 数位dp模板】

    If we sum up every digit of a number and the result can be exactly divided by 10, we say this number ...

  2. sscanf的最基础用法(非原创)

    1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 5 int main(){ 6 ch ...

  3. IPC$入侵

    一 唠叨一下: 网上关于ipc$入侵的文章可谓多如牛毛,而且也不乏优秀之作,攻击步骤甚至可以说已经成为经典的模式,因此也没人愿意再把这已经成为定式的东西拿出来摆弄. 二 什么是ipc$ IPC$(In ...

  4. js map(Number) All In One

    js map(Number) All In One map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值. let newArray = arr.map(callb ...

  5. TypeScript tuple 元组

    TypeScript tuple 元组 元组类型允许您用固定数量的元素表示数组,这些元素的类型是已知的,但不必相同. "use strict"; /** * * @author x ...

  6. component & slot

    component & slot <template> <div class="myHeaderContainer"> <header cla ...

  7. multi selects & mutually exclusive

    multi selects & mutually exclusive 互斥 selects import React, { useState, // useEffect, // useRef, ...

  8. parcel bug & not support normal import React & ReactDOM module

    bug report not support normal import React & ReactDOM module, why Code Sample OK import * as Rea ...

  9. BTC暴涨市值仅次于亚马逊,NGK推出新人助力空投,直接免费送VAST!

    数据显示,在谷歌搜索中,关键词"BTC"的全球搜索指数在过去一周达到满值100点.特斯拉"加持"下,比特币重启暴涨模式,最高报价48126美金单价,非小号数据显 ...

  10. redis源码之dict

    大家都知道redis默认是16个db,但是这些db底层的设计结构是什么样的呢? 我们来简单的看一下源码,重要的字段都有所注释 typedef struct redisDb { dict *dict; ...