zoukankan      html  css  js  c++  java
  • 子查询优化--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  permissionG
    *************************** 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  rolepermissionG
    *************************** 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_roleG
    *************************** 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 profilesG
    *************************** 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 profilesG
    *************************** 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 profilesG
    *************************** 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_roleG  #查看索引
    *************************** 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 rolepermissionG  #查看索引
    *************************** 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 profilesG*************************** 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)
  • 相关阅读:
    会话技术
    Http
    tomcat
    xml
    javascript
    css
    Html
    递归
    二叉树的相关复习
    vim学习
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/9076316.html
Copyright © 2011-2022 走看看