SQL优化

1.为什么要对SQL语句进行优化

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

2.SQL优化的步骤

2.1.查看SQL执行频率

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

如下命令显示了当前session(连接)中所有参数的值(也就是不同的SQL语句执行的频次):

show status like 'Com_______';

参数 含义
Com_select 执行 select 操作的次数,一次查询只累加 1。
Com_insert 执行 INSERT 操作的次数,对于批量插入的 INSERT 操作,只累加一次。
Com_update 执行 UPDATE 操作的次数。
Com_delete 执行 DELETE 操作的次数。
Innodb_rows_read select 查询返回的行数。
Innodb_rows_inserted 执行 INSERT 操作插入的行数。
Innodb_rows_updated 执行 UPDATE 操作更新的行数。
Innodb_rows_deleted 执行 DELETE 操作删除的行数。
Connections 试图连接 MySQL 服务器的次数。
Uptime 服务器工作时间。
Slow_queries 慢查询的次数。

如下命令显示整个数据库从启动至今的不同SQL语句的执行频次统计结果:

show global status like 'Com_______';

还可以通过如下命令,针对于Innodb存储引擎SQL语句执行频次统计查询:

show status like 'innodb_rows_%';

根据如上指令我们可以看出数据库是以什么操作为主。

2.2.定位低效率执行SQL

我们可以通过以下两种方式来定位执行效率低的SQL语句。

  • 慢查询日志:通过慢查询日志定位那些执行效率低的SQL语句,用–log–slow-queries[=file_name]选项启动时,mysqld写一个包含所有执行时间超过long_query_time秒的SQL语句的日志文件。

  • 通过命令 show processlist用来查看当前MySQL在进行的线程,包括线程的状态,是否锁表等,可以实时的查看SQL的执行情况,同时对一些锁表操作进行优化。慢查询日志是在查询结束后才记录,所以在应用反映执行效率出现问题的时候查询慢查询日志并不能定位到问题。

    执行show processlist;命令来查看一下

    列说明:

    id:用户登录时,系统分配中的connection_id,可以使用函数connect_id()查看

    user:显示当前用户,如果不是root,这个命令只显示用户权限范围内的sql语句

    host:显示这个语句时从那个ip的那个端口上发的,可以用来追踪出现问题语句的用户

    db:显示这个进程目前连接的是那个数据库

    command:显示当前连接执行的命令,一般取值为休眠sleep,查询query,连接connect

    time:显示这个状态持续的时间,单位是秒(时间的开始时间是依据show processlist;命令执行后)

    state:显示使用当前连接的sql语句的状态,很重要的列,state描述的是语句执行中的某一个状态,一个sql语句,以查询为例,可能需要经过copying to tmp table resultsending data等状态才可以完成

    info:显示sql语句,是判断问题语句的重要依据

    演示案例:

    创建一张t_user表,往表中插入300万条数据,对其中的一条数据进行精确查询。在查询的过程中,我们通过执行show processlist;命令,看是否能看到执行的查询语句

    CREATE TABLE `t_user`(id int PRIMARY KEY AUTO_INCREMENT,username varchar(20),password varchar(20),birthday date,sex varchar(10),age int,address varchar(255)
    );
    

    详细如下所示:

    有上面的建表语句可以看出来,表中的password列并没有设置索引。所以在查询的时候回比较慢。在执行查询语句后,再通过show processlist;名令来查看当前在进行的线程。如果查询速度慢的话,我们就可以在返回结果中看到这个线程以及线程相关的详细信息。

    select * from t_user where password = '11111';
    

2.3.explain分析执行计划

使用方式:

我们可以通过explain或者desc命令获取MySQL如何执行select语句的信息,包括select语句执行过程中如何连接和连接的顺序

查询SQL语句的执行计划:

explain select * from t_user where id = 11111;

explain select * from t_user where password = '11111';

列的含义:

字段 含义
id select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。
select_type 表示 SELECT 的类型,常见的取值有 SIMPLE(简单表,即不使用表连接或者子查询)、 PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或者后面的查询语 句)、SUBQUERY(子查询中的第一个 SELECT)等
table 输出结果集的表
type 表示表的连接类型,性能由好到差的连接类型为( system —> const -----> eq_ref ------> ref -------> ref_or_null----> index_merge —> index_subquery -----> range -----> index ------> all )
possible_keys 表示查询时,可能使用的索引
key 表示实际使用的索引
key_len 索引字段的长度
rows 扫描行的数量
extra 执行情况的说明和描述
ref 引用

explain属性说明:

准备工作,设计三张表。详细如下:

CREATE TABLE `t_role` (
`id` varchar(32) NOT NULL,
`role_name` varchar(255) DEFAULT NULL,
`role_code` varchar(255) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_role_name` (`role_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `t_user` (
`id` varchar(32) NOT NULL,
`username` varchar(45) NOT NULL,
`password` varchar(96) NOT NULL,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_user_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(32) DEFAULT NULL,
`role_id` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_ur_user_id` (`user_id`),
KEY `fk_ur_role_id` (`role_id`),
CONSTRAINT `fk_ur_role_id` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_ur_user_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;INSERT INTO t_role (id, role_name, role_code, description) VALUES('10', '超 级管理员', 'super', '超级管理员');
INSERT INTO t_role (id, role_name, role_code, description) VALUES('5', '学 生', 'student', '学生');
INSERT INTO t_role (id, role_name, role_code, description) VALUES('7', '老 师', 'teacher', '老师');
INSERT INTO t_role (id, role_name, role_code, description) VALUES('8', '教 学管理员', 'teachmanager', '教学管理员');
INSERT INTO t_role (id, role_name, role_code, description) VALUES('9', '管 理员', 'admin', '管理员');INSERT INTO t_user (id, username, password, name) VALUES('1', 'super', '$2a$10$TJ4TmCdK.X4wv/tCqHW14.w70U3CC33CeVncD3SLmyMXMknstqKRe', ' 超级管理员');
INSERT INTO t_user (id, username, password, name) VALUES('2', 'admin', '$2a$10$TJ4TmCdK.X4wv/tCqHW14.w70U3CC33CeVncD3SLmyMXMknstqKRe', ' 系统管理员');
INSERT INTO t_user (id, username, password, name) VALUES('3', 'itcast', '$2a$10$8qmaHgUFUAmPR5pOuWhYWOr291WJYjHelUlYn07k5ELF8ZCrW0Cui', 'test02');
INSERT INTO t_user (id, username, password, name) VALUES('4', 'stu1', '$2a$10$pLtt2KDAFpwTWLjNsmTEi.oU1yOZyIn9XkziK/y/spH5rftCpUMZa', '学 生1');
INSERT INTO t_user (id, username, password, name) VALUES('5', 'stu2', '$2a$10$nxPKkYSez7uz2YQYUnwhR.z57km3yqKn3Hr/p1FR6ZKgc18u.Tvqm', '学 生2');
INSERT INTO t_user (id, username, password, name) VALUES('6', 't1', '$2a$10$TJ4TmCdK.X4wv/tCqHW14.w70U3CC33CeVncD3SLmyMXMknstqKRe', '老师 1');INSERT INTO user_role (id, user_id, role_id) VALUES(1, '1', '5');
INSERT INTO user_role (id, user_id, role_id) VALUES(2, '1', '7');
INSERT INTO user_role (id, user_id, role_id) VALUES(3, '2', '8');
INSERT INTO user_role (id, user_id, role_id) VALUES(4, '3', '9');
INSERT INTO user_role (id, user_id, role_id) VALUES(5, '4', '8');
INSERT INTO user_role (id, user_id, role_id) VALUES(6, '5', '10');

如下图是三张表的关系图:
t_user:用户表

t_role:角色表

user_role:用户角色表

用户表与角色表之间的关系为多对多的关系,user_role即为它们的中间表

explain-id:

id字段是select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。id情况有三种:

  • id相同表示加载表的顺序是从上到下的

    例如:

    explain select * from t_role r,t_user u,user_role ur where r.id = ur.role_id and u.id = ur.user_id;
    

  • id不同id值越大,优先级别越来越高,越先被执行

    例如:

    EXPLAIN SELECT * FROM t_role WHERE id = (SELECT role_id FROM user_role WHERE user_id = (SELECT id FROM t_user WHERE username = 'stu1'));
    

  • id有相同,也有不同,同时存在。id相同的可以认为是一组,从上往下执行。在所有的组中,id的值越大,优先级越高,越先执行

    例如:

    EXPLAIN SELECT * FROM t_role r , (SELECT * FROM user_role ur WHERE ur.`user_id` = '2') a WHERE r.id = a.role_id ;
    

explain-select_type:

表示SELECT的类型,常见的取值,如下所示:

执行效率,从上倒下递减

select_type 含义
SIMPLE 简单的select查询,查询中不包含子查询或者UNION(联合查询)
PRIMARY 查询中若包含了子查询,最外层查询标记为该标识
SUBQUERY 在select 或 where 列表中包含了子查询
DERIVED 在from列表中包含的子查询,被标记为DERIVED(衍生)MYSQL会递归执行这些子查询,把结果放到临时表中
UNION 若第二个 select 出现在 UNION 之后,则标记为UNION;若UNION包含在FROM子句的子查询中,外层select将被标记为:DERIVED
UNION RESULT 从UNION表获取结果的select
  • SIMPLE

  • PRIMARY、SUBQUERY

  • DERIVED

  • UNION、UNION RESULT

explain-select_table:

展示该行属于那张表

explain-type:

type:显示的是访问类型,是较为重要的一个指标,可取值为:

type 含义
NULL MySQL不访问任何表,索引。直接返回结果
system 表中只有一行数据(等于系统表),这个是const类型的特例,一般不会出现
const 表示通过索引一次就找到了,const用于比较primary key 或者 unique索引。应为只匹配一行数据所以很快。如将主键置于where列表中,MySQL就能将该查询转换为一个常量。const用于将主键或唯一索引的所有其他部分常量值进行比较
eq_ref 类似ref,区别在于使用的是唯一性索引,使用主键的关联查询,关联查询出的记录只有一条。常见于主键或唯一索引扫描
ref 非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,返回所有匹配某个单独值的所有行(多个)
range 只检索给定返回的行,使用一个索引来选择行。where 之后出现between,<,>,in等操作
index index与ALL的区别为:index类型只是遍历了索引树,通常比ALL快,ALL是遍历数据文件
ALL 将遍历全表以找到匹配的行
  • NULL

  • system

  • const

  • eq_ref

  • ref

  • index

  • ALL

结果值从最好到最坏依次是:

NULL > system > const > eq_ref > ref > range > index > all

完整的:NULL > system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

一般来说,我们需要保证查询至少达到range级别,最好达到ref。

explain-key:

possible_keys:显示可能应用在这张表的索引,一个或者多个

key:实际使用的索引,如果为null,则没有使用索引。

key_len:表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下越短越好。

explain-rows:

扫描行的数量

explain-extra:

其他额外的执行计划信息,在该列显示

extra 含义
using file sort 说明mysql会对数据使用一个外部的索引排序,而不是按照表的索引顺序进行读取。称为文件排序,效率低
using temporary 使用临时表保存中间结果,MySQL在对查询结果排序时使用临时表,常见于order by和 group by 效率低
using index 表示相应的select操作使用了覆盖索引,避免访问表的数据行,效率高

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4xZNmoT-1614603889433)(/Users/jiangnan/Library/Application Support/typora-user-images/image-20210301202031788.png)]

2.3.show profile分析SQL

Mysql从5.0.37版本开始增加了对 show profiles 和 show profile 语句的支持。show profiles 能够在做SQL优化时帮助我们了解时间都耗费在什么地方。

通过 select @@have_profiling;命令查看当前MySQL是否支持profile:

YES:支持
NO:不支持

通过select @@profiling;命令查看profiling是否开启,默认是关闭的,可以通过set profiling = 1;命令在Session级别开启profiling:

profiling开启后,执行一些SQL语句。再通过show profiles;命令来查看这些SQL语句再执行过程中耗时记录:

通过 show profile for query query_id; 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间:

Sending data 状态表示MySQL线程开始访问数据行并把结果返回给客户端,而不仅仅是返回个客户端。由于 在Sending data状态下,MySQL线程往往需要做大量的磁盘读取操作,所以经常是整各查询中耗时最长的状态。

2.4.trace分析优化器执行计划

MySQL5.6提供对SQL的追踪trace,通过trace文件能够进行近一步了解优化器执行的计划

首先我们要打开trace,设置格式为JSON,并设置trace文件最大能够使用的内存大小,避免解析过程中因为默认内存过小而不能完整的展示

set optimizer_trace = 'enabled=on',end_markers_in_json=on;
set optimizer_trace_max_mem_size = 1000000;

执行一条SQL语句

select * from t_user;

检查information_schema.optimizer_trace就可以知道MySQL是如何执行SQL的

select * from information_schema.optimizer_trace\G;

SQL优化的详细步骤及工具的使用相关推荐

  1. 图解 免费安装 SQL Server 2005 详细步骤

    广场 登录 注册 关注此空间 S-park 欢迎来到施帕克公园 2009-05-13 18:14 [原创]图解 免费安装 SQL Server 2005 详细步骤 转载本文请详细阅读原创文章版权声明 ...

  2. Win8 用U盘安装(图文详细步骤+准备工具+使用心得)

    Win8的预览版已经出来好久了,相信许多爱折腾的同志们早已经体验到Win8的乐趣了,我也用了几种方法安装Win8,今天就详细说说用U盘安装的步骤,好了废话不多说现在就开始吧. 1.首先你得有台电脑(这 ...

  3. WIN7 32/64位安装SQL Server 2005详细步骤(图文)

    由于工作需要,今天要在电脑上安装SQL Server 2005.以往的项目都是使用Oracle,MS的数据库还真的没怎么用过,安装Oracle已经轻车熟路,但装SQL Server好像还有点小麻烦,所 ...

  4. 高级SQL优化(三) 常用优化工具 ——《12年资深DBA教你Oracle开发与优化——性能优化部分》...

    目录: Oracle数据完整性和锁机制  索引及优化之表分析  表分析.约束及表间关系  Oracle体系结构1 Oracle体系结构2  海量数据库及分区1  海量数据库及分区2  海量数据库及分区 ...

  5. 从一条巨慢SQL看基于Oracle的SQL优化(重磅彩蛋+PPT)

    本文根据DBAplus社群第110期线上分享整理而成,文末还有好书送哦~ 讲师介绍 丁俊 新炬网络首席性能优化专家 SQL审核产品经理 DBAplus社群联合发起人.<剑破冰山-Oracle开发 ...

  6. 【爱加密】Android App应用安全加固详细步骤

    原文地址:点击打开链接 随着各种牌子手机的不断推出,各种Android手机应用,即Android App也是满天飞.但是,在这个山寨.黑客遍布的世界,如何保证Android App的安全是广大Andr ...

  7. u深度u盘安装服务器系统,u深度u盘装win7系统详细步骤

    u深度u盘装win7系统详细步骤 更新时间:2015-12-18 编辑:jcwl2015 windows 7操作系统刚发布,相信曾经有不少喜欢新系统的用户会从微软官网下载所发布的原版win7系统镜像文 ...

  8. 超详细图解!【MySQL进阶篇】SQL优化-索引-存储引擎

    1. Mysql的体系结构概览 整个MySQL Server由以下组成 Connection Pool : 连接池组件 Management Services & Utilities : 管理 ...

  9. SQL优化指南——优化工具使用

    SQL优化场景有单纯场景与复杂场景之分,不同场景有不同场景的优化工具与手段,我们在优化sql语句时应该先判断属于哪一种场景,根据场景选择优化途径,不要盲目地去优化sql语句,否则得不偿失. 1.单纯场 ...

最新文章

  1. android开发(30) 使用WebView,点击网页中的链接建立QQ 临时会话 WPA
  2. BZOJ 1114 Number theory(莫比乌斯反演+预处理)
  3. 微软人工智能平台开源:利用《我的世界》测试AI软件
  4. 动态分辨率是什么意思_什么是1080p、2k、4k?视频基础参数解释
  5. Shell 去掉文本中的空格
  6. mysql 查看锁等待
  7. (28)System Verilog设计UART发送
  8. android nexus 6尺寸,谷歌Nexus 6详细配置曝光 原生Android大杀器
  9. SDN第一次上机作业
  10. 2022年R2移动式压力容器充装操作证考试题库及答案
  11. C51最小单片机系统
  12. gird和flex布局
  13. 鸿蒙系统报名选择一个应用,申请鸿蒙系统有一个应用选择怎么选择呢
  14. 神奇的主力成本线!居然能将主力成本运筹帷幄?!
  15. 【python量化交易学习】从tushare获取股票交易数据,存入后再从mysql或excel读取数据,筛选股票,用pyecharts画出K线图。
  16. Haxe FD 开发学习
  17. Linux进程间关系之守护进程
  18. Codeforces Contest 1144 E Median String —— 水题
  19. 大数据时代下,跨境电商如何利用数据实现快速发展
  20. 06-软件测试计划及测试说明

热门文章

  1. 网络安全:网络信息安全的概述.
  2. 写给自己,学习如逆水行舟,不进则退
  3. python-机器学习-波士顿房价回归分析
  4. 工作中可能用到的——集中式版本控制系统SVN
  5. Oracle导入dmp数据
  6. Note: Bimodal Content Defined Chunking for Backup Streams
  7. 4个图片无损压缩工具,快速批量压缩图片,图片高清不糊
  8. 非匿名方式访问远程的com+
  9. DBlink 创建 删除 脚本
  10. 关于调用百度AI接口进行图片识别的实现(C#)