SQL优化:SQL的分析和优化过程

本文记录SQL的优化分析过程,需用到MySQL的案例库sakila,下载地址是http://downloads.mysql.com/docs/sakila.db.zip。压缩包包括3个文件:sakila-schema.sql、sakila-data.sql、sakila.mwb,我们主要用到前两个,分别是sakila库的表结构创建和表数据。

一.show status的使用

通过show status我们可以了解各种SQL的执行频率。
比如执行如下命令:

SHOW STATUS LIKE 'Com_%';

SQL优化:SQL的分析和优化过程_第1张图片
Com_xxx表示每个xxx语句执行的次数,主要看以下几个参数:
Com_select:执行select操作的次数,一次查询累加1.
Com_insert:执行insert操作次数,对于批量插入,只累加一次。
Com_update:执行update操作的次数。
Com_delete:执行delete操作的次数。
上面这些参数对于所有存储引擎的表操作都会进行累计。

执行如下语句可获取InnoDB存储引擎相关的统计数据:

SHOW STATUS LIKE 'Innodb_%';

SQL优化:SQL的分析和优化过程_第2张图片
同时我们重点需要关注如下4个参数:
Innodb_rows_read:select查询返回的行数。
Innodb_rows_inserted:执行insert操作插入的行数。
Innodb_rows_updated:执行update操作更新的行数。
Innodb_rows_deleted:执行delete操作删除的行数。

通过如上两个执行语句,我们可以了解到当前数据库是插入更新操作较多还是查询操作较多。对于更新操作的统计,是对执行次数的统计,不论是提交还是回滚都会进行累加。
对于事务型的应用,通过Com_commit和Com_rollback可以了解事务提交和回滚的情况,对于回滚操作非常频繁的情况,可能程序的编写就存在着问题。

二.定位执行效率较低的SQL

可通过慢查询日志和SHOW PROCESSLIST指令两种方式。

  • 通过设置long_query_time(单位:秒)时间,任何执行时间超过该值的SQL语句都会被记录在一慢查询日志中。
  • 通过SHOW PROCESSLIST命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等。

三.通过explain分析低效SQL的执行计划

在获取到效率低的SQL后,可通过explain或者desc命令获取MySQL如何执行select语句的信息,例如:

EXPLAIN SELECT SUM(amount) FROM customer a,payment b WHERE 1=1 AND a.customer_id=b.customer_id AND email=‘[email protected]’;
SQL优化:SQL的分析和优化过程_第3张图片

对执行结果的每个字段说明下:

  • select_type:表示select的类型,常见的取值有SIMPLE(简单表,不使用表连接或者子查询)、PRIMARY(外层查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个select)。
  • table:输出结果集的表。
  • type:表示MySQL在表中找到所需行的方式,常见取值有ALL、index、range、ref、eq_ref、const,system、NULL,从左到右性能由最差到最好。
    (1)type=ALL,全表扫描,MySQL遍历全表来找到匹配的行:
    SQL优化:SQL的分析和优化过程_第4张图片
    (2)type=index,索引全扫描,MySQL遍历整个索引来查询匹配的行:
    SQL优化:SQL的分析和优化过程_第5张图片
    (3)type=range,索引范围扫描,常见于<、<=、>、>=、between等操作符:
    SQL优化:SQL的分析和优化过程_第6张图片
    (4)type=ref,使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录:
    SQL优化:SQL的分析和优化过程_第7张图片
    索引idx_fk_customer_id是非唯一索引,查询条件是等值查询,所以扫描索引的类型为ref。
    ref还经常出现在join操作中:
    SQL优化:SQL的分析和优化过程_第8张图片
    (5)type=eq_ref,类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者unique index作为关联条件。
    SQL优化:SQL的分析和优化过程_第9张图片
    (6)type=const/system,单表中最多有一个匹配行,查询非常迅速,所以这个匹配行中的其它列的值可以被优化器在当前查询中当作常量处理,比如根据主键或者唯一索引进行查询:
    SQL优化:SQL的分析和优化过程_第10张图片
    通过唯一索引uk_email访问时,类型type为const。
    (7)type=NULL,MySQL不用访问表或者索引,直接就能得到结果:
    SQL优化:SQL的分析和优化过程_第11张图片
    类型type还有其它值,如ref_or_null(与ref类似,区别在于条件中包含对NULL的查询)、index_merge(索引合并优化)、unique_subquery(in的后面是一个查询主键字段的子查询)、index_subquery(与unique_subquery类似,区别在于in的后面是查询非唯一索引字段的子查询)等。
  • possible_keys:表示查询时可能用的索引。
  • key:表示实际使用的索引。
  • key_len:使用到索引字段的长度。
  • rows:扫描行的数量。
  • Extra:执行情况的说明和描述,包含不适合在其它列中显示但是对执行计划非常重要的额外信息。
    有时候,仅仅通过explain分析执行计划并不能很快定位SQL的问题,这时我们还可以选择profile联合分析。

四.通过show profile分析SQL

通过SELECT @@have_profiling; 可查看profiling是否开启:
在这里插入图片描述
如未开启可通过SET profiling=1; 开启。
通过profile,我们能更清楚地了解SQL的执行过程,能知道SQL的执行时间都耗费到哪里去了。
在InnoDB引擎的payment上,执行count(*)查询:

SELECT COUNT(*) FROM payment;

执行完成后,通过show profiles语句,可看到该条SQL的Query_ID:
SQL优化:SQL的分析和优化过程_第12张图片
通过SHOW PROFILE FOR QUERY 41; 语句能够看到执行过程中线程的每个状态和消耗时间:
SQL优化:SQL的分析和优化过程_第13张图片
在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io、context switch、page faults 等明细类型来查看MySQL在使用什么资源上消耗了过多时间,例如,查看CPU上耗费的时间:

SHOW PROFILE cpu FOR QUERY 41;

SQL优化:SQL的分析和优化过程_第14张图片
通过如上步骤,就可以定位出有问题的SQL 并制定相应的优化措施了。

你可能感兴趣的:(MySQL)