在应用的的开发过程中,由于初期数据量小,开发人员写 SQL 语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多 SQL 语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的 SQL 语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化.
为什么这么说呢?因为在MySQL查询语句中,语法比较的通用吗,要想得到一个数据集可以使用不同的查询语句!
例如我们需要查询一个数据表有多少行数据集?
1、暴力搜索
select count(*) from data;
这样虽然也可以达到效果,但是用 "SELECT * " 数据库需要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
增大网络开销,* 有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增长。特别是MySQL和应用程序不在同一台机器,这种开销非常明显。
2、限定字段查询
select count(id) from data;
这里的id是一个递增的序列,查询效果确实有所提升。
MySQL的优化方式有很多,大致我们可以从以下几点来优化MySQL:
从设计上优化
从查询上优化
从索引上优化
从存储上优化
查看SQL执行频率
MySQL 客户端连接成功后,通过 show [session|global] status 命令可以查看服务器状态信息。通过查看状态信息可以查看对当前数据库的主要操作类型。
--下面的命令显示了当前 session 中所有统计参数的值 show session status like 'Com_______'; -- 查看当前会话统计结果 show global status like 'Com_______'; -- 查看自数据库上次启动至今统计结果 show status like 'Innodb_rows_%’; -- 查看针对Innodb引擎的统计结果
定位低效率执行SQL
可以通过以下两种方式定位执行效率较低的 SQL 语句。
慢查询日志 : 通过慢查询日志定位那些执行效率较低的 SQL 语句。
show processlist:该命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看 SQL 的执行情况,同时对一些锁表操作进行优化。
-- 查看慢日志配置信息 show variables like '%slow_query_log%’; -- 开启慢日志查询 set global slow_query_log=1; -- 查看慢日志记录SQL的最低阈值时间 show variables like 'long_query_time%’; -- 修改慢日志记录SQL的最低阈值时间 set global long_query_time=4;
show processlist;
1) id列,用户登录mysql时,系统分配的"connection_id",可以使用函数connection_id()查看
2) user列,显示当前用户。如果不是root,这个命令就只显示用户权限范围的sql语句
3) host列,显示这个语句是从哪个ip的哪个端口上发的,可以用来跟踪出现问题语句的用户
4) db列,显示这个进程目前连接的是哪个数据库
5) command列,显示当前连接的执行的命令,一般取值为休眠(sleep),查询(query),连接(connect)等
6) time列,显示这个状态持续的时间,单位是秒
7) state列,显示使用当前连接的sql语句的状态,很重要的列。state描述的是语句执行中的某一个状态。一个sql语句,以查询为例,可能需要经过copying to tmp table、sorting result、sending data等状态才可以完成
8) info列,显示这个sql语句,是判断问题语句的一个重要依据
explain分析执行计划
通过以上步骤查询到效率低的 SQL 语句后,可以通过 EXPLAIN命令获取 MySQL如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。
-- 准备测试数据 create database mydb13_optimize; use mydb13_optimize; 执行sql脚本sql_optimize.sql添加数据 explain select * from user where uid = 1;
id 字段是 select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。id 情况有三种:
1、id 相同表示加载表的顺序是从上到下
explain select * from user u, user_role ur, role r where u.uid = ur.uid and ur.rid = r.rid ;
2、 id 不同id值越大,优先级越高,越先被执行。
explain select * from role where rid = (select rid from user_role where uid = (select uid from user where uname = '张飞'))
3、 id 有相同,也有不同,同时存在。id相同的可以认为是一组,从上往下顺序执行;在所有的组中,id的值越大,优先级越高,越先执行。
表示 SELECT 的类型,常见的取值,如下表所示:
type 显示的是访问类型,是较为重要的一个指标,可取值为:
结果值从最好到最坏以此是:system > const > eq_ref > ref > range > index > ALL
其他的额外的执行计划信息,在该列展示 。
Mysql从5.0.37版本开始增加了对 show profiles 和 show profile 语句的支持。show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。
通过 have_profiling 参数,能够看到当前MySQL是否支持profile:
select @@have_profiling; set profiling=1; -- 开启profiling 开关;
通过profile,我们能够更清楚地了解SQL执行的过程。首先,我们可以执行一系列的操作
show databases; use mydb13_optimize; show tables; select * from user where id < 2; select count(*) from user;
执行完上述命令之后,再执行show profiles 指令, 来查看SQL语句执行的耗时:
show profiles;
通过show profile for query query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间:
show profile for query 8;
在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io 、context switch、page faults等明细类型类查看MySQL在使用什么资源上耗费了过高的时间。例如,选择查看CPU的耗费时间 :
show profile cpu for query 133;
在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io 、context switch、page faults等明细类型类查看MySQL在使用什么资源上耗费了过高的时间。例如,选择查看CPU的耗费时间 :
trace分析优化器执行计划
MySQL5.6提供了对SQL的跟踪trace, 通过trace文件能够进一步了解为什么优化器选择A计划, 而不是选择B计划
SET optimizer_trace="enabled=on",end_markers_in_json=on;
set optimizer_trace_max_mem_size=1000000;
执行SQL语句 :
select * from user where uid < 2;
最后, 检查information_schema.optimizer_trace就可以知道MySQL是如何执行SQL的 :
select * from information_schema.optimizer_trace\G;