子查询优化--explain与profiling分析语句
今天想的利用explain与progiling分析下语句然后进行优化。本文重点是如何通过explain与profiling分析SQL执行过程与性能。进而明白索引的重要性。
表的关系如下所示:

原始的查询SQL:(根据用户的ID查看用户的权限)
SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role
WHERE userid = 'b33b938faada40aeac2b5ca228336473'))
-----------------------------------不加索引的分析以及测试-----------------------------------------
1.分析
首先将三个表的索引全部去掉 (只剩下主键索引)
查看三个表的索引:
mysql> SHOW INDEX FROM permission\G
*************************** 1. row ***************************
Table: permission
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: permissionID
Collation: A
Cardinality: 50
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec) mysql> SHOW INDEX FROM rolepermission\G
*************************** 1. row ***************************
Table: rolepermission
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: rolePermissionId
Collation: A
Cardinality: 66
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec) mysql> SHOW INDEX FROM user_role\G
*************************** 1. row ***************************
Table: user_role
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: userRoleID
Collation: A
Cardinality: 4
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec) mysql>
1. explain 分析上面SQL的执行计划:
EXPLAIN
SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role
WHERE userid = 'b33b938faada40aeac2b5ca228336473'))
结果:

分析:
ID越大越先执行,ID相同的按顺序从上向下执行。
查询rolepermission和userrole都是全表扫描(type为All),且未用到任何索引,只有查询permission用到了主键索引。且看到后连个表的命中率也都比较低。
关于更全的参数解释参考:https://www.cnblogs.com/qlqwjy/p/7767479.html
2.通过profiling分析语句:
0.可以在执行之前清空查询缓存
reset query cache;
1、 开启 profiling 参数
root@localhost : (none) 10:53:11> set profiling=1;
Query OK, 0 rows affected (0.00 sec)
通过执行 “set profiling”命令,可以开启关闭 Query Profiler 功能。
2.执行query:
SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role
WHERE userid = 'b33b938faada40aeac2b5ca228336473'))
3、获取系统中保存的所有 Query 的 profile 概要信息
mysql> show profiles\G
*************************** 1. row **************************
Query_ID: 1
Duration: 0.01237475
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role 1 row in set, 1 warning (0.00 sec)
分析 : 可以看到总共花了 12ms。
通过执行 “SHOW PROFILE” 命令获取当前系统中保存的多个 Query 的 profile 的概要信息。
4、针对单个 Query 获取详细的 profile 信息。
在获取到概要信息之后,我们就可以根据概要信息中的 Query_ID 来获取某个 Query 在执行过程中
详细的 profile 信息了,具体操作如下(1是上面的queryID)
mysql> show profile for query 1;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000819 |
| checking permissions | 0.000536 |
| checking permissions | 0.000519 |
| checking permissions | 0.000525 |
| Opening tables | 0.000700 |
| init | 0.000958 |
| System lock | 0.000989 |
| optimizing | 0.000557 |
| statistics | 0.000587 |
| preparing | 0.000519 |
| executing | 0.000492 |
| Sending data | 0.001388 |
| end | 0.000512 |
| query end | 0.000492 |
| removing tmp table | 0.000492 |
| query end | 0.000479 |
| closing tables | 0.000517 |
| freeing items | 0.000720 |
| cleaning up | 0.000577 |
+----------------------+----------+
19 rows in set, 1 warning (0.00 sec)
如果想查看cpu,io等信息更具体的信息可以:
mysql> show profile cpu, block io for query 1;
+----------------------+----------+----------+------------+--------------+-----
---------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Bloc
_ops_out |
+----------------------+----------+----------+------------+--------------+-----
---------+
| starting | 0.000819 | 0.000000 | 0.000000 | NULL |
NULL |
| checking permissions | 0.000536 | 0.000000 | 0.000000 | NULL |
NULL |
| checking permissions | 0.000519 | 0.000000 | 0.000000 | NULL |
NULL |
| checking permissions | 0.000525 | 0.000000 | 0.000000 | NULL |
NULL |
| Opening tables | 0.000700 | 0.000000 | 0.000000 | NULL |
NULL |
| init | 0.000958 | 0.000000 | 0.000000 | NULL |
NULL |
| System lock | 0.000989 | 0.000000 | 0.000000 | NULL |
NULL |
| optimizing | 0.000557 | 0.000000 | 0.000000 | NULL |
NULL |
| statistics | 0.000587 | 0.000000 | 0.000000 | NULL |
NULL |
| preparing | 0.000519 | 0.000000 | 0.000000 | NULL |
NULL |
| executing | 0.000492 | 0.000000 | 0.000000 | NULL |
NULL |
| Sending data | 0.001388 | 0.000000 | 0.000000 | NULL |
NULL |
| end | 0.000512 | 0.000000 | 0.000000 | NULL |
NULL |
| query end | 0.000492 | 0.000000 | 0.000000 | NULL |
NULL |
| removing tmp table | 0.000492 | 0.000000 | 0.015625 | NULL |
NULL |
| query end | 0.000479 | 0.000000 | 0.000000 | NULL |
NULL |
| closing tables | 0.000517 | 0.000000 | 0.000000 | NULL |
NULL |
| freeing items | 0.000720 | 0.000000 | 0.000000 | NULL |
NULL |
| cleaning up | 0.000577 | 0.000000 | 0.000000 | NULL |
NULL |
+----------------------+----------+----------+------------+--------------+-----
---------+
2.测试修改SQL
将上述子查询SQL改为内连接查询:
SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'b33b938faada40aeac2b5ca228336473'
1.explain分析:
分析:
EXPLAIN
SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'b33b938faada40aeac2b5ca228336473'
结果:

分析:上面的子查询为四次查询,变为内连接查询为3此,且前两个未加索引,最后用到了主键索引。
2.通过profilies查看查询效率:
mysql> show profiles\G
*************************** 1. row ***************************
Query_ID: 1
Duration: 0.02015850
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role *************************** 2. row ***************************
Query_ID: 2
Duration: 0.01072575
Query: EXPLAIN
SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'b33b938faada40aeac2b5ca228336473'
2 rows in set, 1 warning (0.00 sec)
发现变为内连接查询所花费的时间变为原来的一班,原来20ms,现在10ms。
多查询几次,查看效率:
mysql> show profiles\G
*************************** 1. row ***************************
Query_ID: 1
Duration: 0.01448950
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role *************************** 2. row ***************************
Query_ID: 2
Duration: 0.01417150
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role *************************** 3. row ***************************
Query_ID: 3
Duration: 0.01466100
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role *************************** 4. row ***************************
Query_ID: 4
Duration: 0.01308100
Query: SELECT *
FROM permission
inner join rolepermission
on permission.permissionID = rolepermission.permissionId
INNER join user_role
on rolepermission.roleId = user_role.roleID
where user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
*************************** 5. row ***************************
Query_ID: 5
Duration: 0.01334675
Query: SELECT *
FROM permission
inner join rolepermission
on permission.permissionID = rolepermission.permissionId
INNER join user_role
on rolepermission.roleId = user_role.roleID
where user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
*************************** 6. row ***************************
Query_ID: 6
Duration: 0.01289250
Query: SELECT *
FROM permission
inner join rolepermission
on permission.permissionID = rolepermission.permissionId
INNER join user_role
on rolepermission.roleId = user_role.roleID
where user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
6 rows in set, 1 warning (0.00 sec)
前三条是子查询,后3条是内连接,发现内连接稍微快于子查询。
-----------------------------------加索引的分析以及测试-----------------------------------------
0.在上面的表上加上索引
mysql> alter table user_role add index roleIdIndex(roleId); #添加索引
Query OK, 0 rows affected (0.59 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table user_role add index userIdIndex(userId);
Query OK, 0 rows affected (0.53 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table rolepermission add index per_roleIdIndex(roleId);
Query OK, 0 rows affected (0.49 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table rolepermission add index per_perssionIdIndex(permissionId);
Query OK, 0 rows affected (0.38 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> show index from user_role\G #查看索引
*************************** 1. row ***************************
Table: user_role
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: userRoleID
Collation: A
Cardinality: 4
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: user_role
Non_unique: 1
Key_name: roleIdIndex
Seq_in_index: 1
Column_name: roleID
Collation: A
Cardinality: 3
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 3. row ***************************
Table: user_role
Non_unique: 1
Key_name: userIdIndex
Seq_in_index: 1
Column_name: userID
Collation: A
Cardinality: 3
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
3 rows in set (0.01 sec) mysql> show index from rolepermission\G #查看索引
*************************** 1. row ***************************
Table: rolepermission
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: rolePermissionId
Collation: A
Cardinality: 66
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: rolepermission
Non_unique: 1
Key_name: per_roleIdIndex
Seq_in_index: 1
Column_name: roleId
Collation: A
Cardinality: 4
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
*************************** 3. row ***************************
Table: rolepermission
Non_unique: 1
Key_name: per_perssionIdIndex
Seq_in_index: 1
Column_name: permissionId
Collation: A
Cardinality: 52
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
3 rows in set (0.01 sec)
1.针对子查询进行分析
1.explain分析:
EXPLAIN
SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role
WHERE userid = 'a9e65788297e4a8cb68a369522ee5af7'))
结果:

发现加上索引之后查询效果明显提升,三个表到用到索引,且命中率为100%。
2.profile分析:
mysql> show profiles\G*************************** 2. row ***************************
Query_ID: 2
Duration: 0.01505400
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role *************************** 3. row ***************************
Query_ID: 3
Duration: 0.01624350
Query: SELECT *
FROM permission
WHERE permissionid IN(SELECT
permissionid
FROM rolepermission
WHERE roleid IN(SELECT
roleid
FROM user_role 3 rows in set, 1 warning (0.00 sec) mysql>
数据量小没有多大影响。
2.针对显示内连接进行分析
1.explain分析
EXPLAIN
SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
结果:

2.show profile分析
*************************** 4. row ***************************
Query_ID: 4
Duration: 0.01447100
Query: SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
*************************** 5. row ***************************
Query_ID: 5
Duration: 0.01502600
Query: SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
*************************** 6. row ***************************
Query_ID: 6
Duration: 0.01471300
Query: SELECT *
FROM permission
INNER JOIN rolepermission
ON permission.permissionID = rolepermission.permissionId
INNER JOIN user_role
ON rolepermission.roleId = user_role.roleID
WHERE user_role.userID = 'a9e65788297e4a8cb68a369522ee5af7'
6 rows in set, 1 warning (0.00 sec)
子查询优化--explain与profiling分析语句的更多相关文章
- explain和profiling分析查询SQL时间
mysql可以通过profiling命令查看到执行查询SQL消耗的时间. 默认情况下,mysql是关闭profiling的,命令: select @@profiling; +------------- ...
- mysql优化----explain的列分析
sql语句优化: : sql语句的时间花在哪儿? 答: 等待时间 , 执行时间. 等待时间:看是不是被锁住了,那就不是语句层面了是服务端层面了,看连接数内存. 执行时间:到底取出多少行,一次性取出1万 ...
- 【MySQL】MySQL中针对大数据量常用技术_创建索引+缓存配置+分库分表+子查询优化(转载)
原文地址:http://blog.csdn.net/zwan0518/article/details/11972853 目录(?)[-] 一查询优化 1创建索引 2缓存的配置 3slow_query_ ...
- 标量子查询优化(用group by 代替distinct)
标量子查询优化 当使用另外一个SELECT 语句来产生结果中的一列的值的时候,这个查询必须只能返回一行一列的值.这种类型的子查询被称为标量子查询 在某些情况下可以进行优化以减少标量子查询的重复执行,但 ...
- MySQL慢查询优化 EXPLAIN详解
我们平台过一段时间就会把生产数据库的慢查询导出来分析,要嘛修改写法,要嘛新增索引.以下是一些笔记.总结整理 慢查询排查 show status; // 查询mysql ...
- postgresql子查询优化(提升子查询)
问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...
- MySQL的EXPLAIN命令用于SQL语句的查询执行计划
MySQL的EXPLAIN命令用于SQL语句的查询执行计划(QEP).这条命令的输出结果能够让我们了解MySQL 优化器是如何执行SQL 语句的.这条命令并没有提供任何调整建议,但它能够提供重要的信息 ...
- SQL优化之慢查询和explain以及性能分析
性能优化的思路 首先需要使用慢查询功能,去获取所有查询时间比较长的SQL语句 使用explain去查看该sql的执行计划 使用show profile去查看该sql执行时的性能问题 MySQL性能优化 ...
- MySQL实验 子查询优化双参数limit
MySQL实验 子查询优化双参数limit 没想到双参数limit还有优化的余地,为了亲眼见到,今天来亲自实验一下. 实验准备 使用MySQL官方的大数据库employees进行实验,导入该示例库 ...
随机推荐
- C++模式学习------工厂模式
工厂模式属于创建型模式,大致可以分为简单工厂模式.抽象工厂模式. 简单工厂模式,它的主要特点是需要在工厂类中做判断,从而创造相应的产品. enum PTYPE { ProdA = , ProdB = ...
- ldap添加memberof支持
安装请查看上一篇博客,传送门:https://www.cnblogs.com/crysmile/p/9470508.html 如果使用LDAP仅仅作为用户统一登录中心,则参考安装文档即可:如果ldap ...
- 题解 P3870 【[TJOI2009]开关】
这个题我愣是交了好几遍没有过...... 后来@_皎月半洒花dalao告诉我说要^儿子节点的tag,然后就明白了...... 行吧,先上题面: 题目描述 现有N(2 ≤ N ≤ 100000)盏灯排成 ...
- C 函数——Day04
C 函数 函数是一组一起执行一个任务的语句.每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数. 您可以把代码划分到不同的函数中.如何划分代码到不同的函数 ...
- P1198 [JSOI2008]最大数
题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前数列的长度.(L>0) ...
- 【刷题】LOJ 6000 「网络流 24 题」搭配飞行员
题目描述 飞行大队有若干个来自各地的驾驶员,专门驾驶一种型号的飞机,这种飞机每架有两个驾驶员,需一个正驾驶员和一个副驾驶员.由于种种原因,例如相互配合的问题,有些驾驶员不能在同一架飞机上飞行,问如何搭 ...
- Unity使用C#实现简单Scoket连接及服务端与客户端通讯
简介: 网络编程是个很有意思的事情,偶然翻出来很久之前刚开始看Socket的时候写的一个实例,贴出来吧 Unity中实现简单的Socket连接,c#中提供了丰富的API,直接上代码. 服务端代码: [ ...
- 【转】嵌入式Linux驱动面试题三道
题一: Linux设备中字符设备与块设备有什么主要的区别? 字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性.字符设备驱动程序通常至少实现open,cl ...
- 洛谷 P4363 [九省联考2018]一双木棋chess 解题报告
P4363 [九省联考2018]一双木棋chess 题目描述 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落 ...
- HDU 1711 Number Sequence (字符串匹配,KMP算法)
HDU 1711 Number Sequence (字符串匹配,KMP算法) Description Given two sequences of numbers : a1, a2, ...... , ...