子查询优化--explain与profiling分析语句

  

  

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

表的关系如下所示:

子查询优化--explain与profiling分析语句

原始的查询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'))

结果:

子查询优化--explain与profiling分析语句

分析:

  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'

结果:

子查询优化--explain与profiling分析语句

分析:上面的子查询为四次查询,变为内连接查询为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'))

结果:

子查询优化--explain与profiling分析语句

发现加上索引之后查询效果明显提升,三个表到用到索引,且命中率为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'

结果:

子查询优化--explain与profiling分析语句

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)
上一篇:mysql中int(3)与int(11)有什么区别吗?


下一篇:flv.js使用(原生js)