【7天玩转MySQL】华为云RDS for MySQL学习笔记 Day04

举报
真爱无敌 发表于 2020/08/01 12:21:48 2020/08/01
【摘要】 【7天玩转MySQL】华为云RDS for MySQL学习笔记 Day04第四天的内容主要是:Select查询目标:了解MySQL的查询语句的支持范围,以及如何获取查询语句的执行计划、一些基本查询语句的优化点和注意事项等。下面进入正题:一、查询基本概念1、查询SQL结构1.1 select查询结构select查询语句结构主要如下所示: 重点注意事项:Select 查询SQL语句可以...

【7天玩转MySQL】华为云RDS for MySQL学习笔记  Day04

第四天的内容主要是:Select查询

目标:了解MySQL的查询语句的支持范围,以及如何获取查询语句的执行计划、一些基本查询语句的优化点和注意事项等。

下面进入正题:

一、查询基本概念

1、查询SQL结构

1.1 select查询结构

select查询语句结构主要如下所示:

     image.png

重点注意事项:Select 查询SQL语句可以只包含部分成员

1.2 select查询结构实例

image.png


2、子查询

  • Derived table

        子查询出现在 Target Table 中,比如:select * from (select sum(a) from t1) T

  • Scalar Operand

        子查询出现在 select expr 中,比如: select (select 1) from t1

  • Comparison

        子查询出现在 where 、 having 条件中,比如: select * from t1 where id IN (select id from t2)

  • 关联子查询

        子查询中引用了外部查询的字段,比如: select * from t1 where id IN (select id from t2 where t2.a=t1.b)

  • 非关联子查询

        子查询没有引用外部查询的字段


3、多表join

  • Inner Join

        查询所有满足 join 条件的记录。

  • Outer Join

        查询所有满足 join 条件的记录,且输出至少一张表的全部记录, Left/Right Join 。

  • Semi Join

        查询是否有至少一条满足 join 条件的记录,对 IN 、 =ANY 、 EXISTS 子查询的一种优化手段。

  • Anti Join

        查询是否不存在满足 join 条件的记录,是对 NOT IN 、 != ALL 、 NOT EXIST 子查询的一种优化手段。


二、查询执行策略

1、表访问方式

表访问方式主要包括:

  • 全表扫描

        主键索引上扫描

  • 索引扫描

        二级索引上扫描

  • 索引Range

        索引上范围扫描

        <、>、<=、>=

  • 索引ref查询

        索引上同一个value查询

        =

2、order by

  • 索引扫描

        索引顺序按 Order by 字段有序,可直接通过扫描索引得到有序结果

        条件:order by 字段满足索引上最左匹配

             如“ order by a, b” ,索引 idx_abc(a , b , c) 可以扫描使用

  • filesort 排序

        查询结果通过 filesort 进行外部排序

        不满足索引扫描条件时使用

        image.png


3、Group by

  • 索引扫描

        通过 Loose Scan 的方式扫描索引去重

        条件:order by 字段满足索引上最左匹配

               如“order by a, b” ,索引 idx_abc(a , b , c) 可以扫描使用

  • 临时表分组

        查询结果保存在一张临时表中,并通过 group by 字段更新 aggregation 字段。

        不满足索引扫描条件时使用

      image.png

4、derived  table

  • Merge

        子查询直接合入外部的查询语句,消除 Derived table

        条件:非关联简单子查询

            如: select * from (select a, b from t1) A order by A.b 可直接改 merge 成: select a, b from t1 order by b

  • 物化

        子查询的结果保持在一张临时表中,供外部查询继续使用。

        条件:非关联子查询

            如: select sum(col_sum) from ( select sum(a) as col_sum from t1 group by b ) A

5、子查询

  • 物化

        子查询的结果保持在一张临时表中,供外部查询继续使用。

        条件:非关联子查询

            如:select * from t1 where a > (select max(b) from t2)

  • SemiJoin

        子查询改写成 semi join 执行

        条件:关联子查询,且是 IN 、 EXISTS 、 =ANY 等查询条件

           如 select * from t1 where a IN (select b from t2) , 会改写成 select t1.* from t1 semi join t2 on t1.a=t2.b

  • 嵌套执行

        内部子查询嵌套在外部查询执行过程中执行,效率最差

        上面两个条件都不满足:

            如:select * from t1 where a > (select max(b) from t2 where t2.b = t1.c)

6、多表join

  • Nest Loop Join (NL)

        相当于两层 for 循环执行,外表的每条记录去内部做扫描查询匹配

        效率最差

  • Block Nest Loop Join (BNL)

        外表的记录存放在 Join Cache 缓存中,内表循环时每条记录去 Join Cache 中查找匹配记录

        Join Cache 的目的是为了减少内表的遍历次数

  • Block Key Access Join (BKA)

        外表的记录存放在 Join Cache 缓存中,然后 Join Cache 中每条记录通过索引查询内部中匹配的记录

  • Hash Join

        外表作为一张 build 表创建 hash map

        内部作为 probe 表在 hash map 中查找匹配记录

三、执行计划分析

1、Explain 分析

1.1 Explain简介

  • 基本用途

    用来展示SQL查询语句的执行计划信息,帮助分析和改进查询语句的执行效率

  • 使用方式

    Explain [format=json/tree] query statement

  • 输出内容

    Explain

1.2 Explain输出内容

  • select type

        SIMPLE 、PRIMARY 、 UNION 、 SUBQUERY 、 DEPENDENT SUBQUERY 、 DERIVED 、 DEPENDENT、DERIVED 

  • Type

        system 、 const 、 eq_ref 、 ref 、 fulltext 、 index 、 range 、 ALL

  • possible_keys

        SQL 语句命中的所有索引

  • Key

        SQL 语句使用的索引

  • Rows

        预估的输出行数

  • Filtered

        过滤条件过滤数据的比例

1.3 Explain实践

1)表访问

  • 全表扫描

    image.png

  • 主键ref

    image.png

  • 主键range

    image.png

  • 覆盖索引扫描

    image.png


2)Order by

  • 索引排序

    image.png

  • FileSort 排序

    image.png


3)Group by

  • 索引排序

    image.png

  • 临时表分组

    image.png


4)Derived table

  • System table

     image.png

  • 物化临时表

    image.png

  • merge

    image.png


5)子查询

  • subquery

    image.png

  • dependent subquery

    image.png

  • semijoin (first match)

    image.png

  • 物化子查询

    image.png


6)多表join

  • Nested loop join

    image.png

  • BNL join

    image.png

  • BKA join

    image.png


2、Optimize trace 分析

2.1 Optimize trace作用

  • 用来分析优化器生成执行计划的详细过程,往往用例分析生产错误执行计划的原因,从而给索引优化提供参考建议。

  • 打开方式

        Set session optimizer_trace="enabled=on";

        set session optimizer_trace_max_mem_size=1000000;

        Execute Your Query statement SQL;

        Select * From Information_Schema.Optimizer_Trace [into outfile“out.txt"];

        Set session optimizer_trace="enabled=off";

2.2 Optimize trace 分析

首先要了解SQL查询的执行过程:

image.png

SQL查询执行阶段:

image.png

SQL查询执行阶段分析:

image.png

2.3 Optimize trace 使用

# 开启跟踪,默认是关闭的
SET optimizer_trace="enabled=on";      
#执行你的sql语句
select ....
#查看trace信息
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
# 执行完你需要的sql语句就可以关闭trace了
SET optimizer_trace="enabled=off";


支持Optimize trace的SQL语句有:

1.SELECT;
2.INSERT or REPLACE (with VALUES or SELECT);
3.UPDATE/DELETE and their multi-table variants;
4.all the previous ones prefixed by EXPLAIN;
5.SET (unless it manipulates the optimizer_trace system variable);
6.DO;
7.DECLARE/CASE/IF/RETURN (stored routines language elements);
8.CALL.


具体Optimize trace 跟踪的json格式信息如下:

select * from test1,test2 where test1.id=test2.id and test1.id>4999900 | {
  "steps": [
    {
      "join_preparation": {           --连接准备
        "select#": 1,                 --join准备的第一步
        "steps": [                    --解析成编号,解析数据库和表
          {
            "expanded_query": "/* select#1 */ select `test1`.`id` AS `id`,`test1`.`k` AS `k`,`test1`.`c` AS `c`,`test1`.`pad` AS `pad`,`test2`.`id` AS `id`,`test2`.`k` AS `k`,`test2`.`c` AS `c`,`test2`.`pad` AS `pad` from `test1` join `test2` where ((`test1`.`id` = `test2`.`id`) and (`test1`.`id` > 4999900))"
          }
        ]
      }
    },
    {
      "join_optimization": {         --join优化
        "select#": 1,
        "steps": [
          {
            "condition_processing": {       --where条件
              "condition": "WHERE",
              "original_condition": "((`test1`.`id` = `test2`.`id`) and (`test1`.`id` > 4999900))",
              "steps": [       --优化的步骤
                {
                  "transformation": "equality_propagation",         --等值优化
                  "resulting_condition": "((`test1`.`id` > 4999900) and multiple equal(`test1`.`id`, `test2`.`id`))"   --把test.id>4999900放到前面,test1.id=test2.id使用多等值连接
                },
                {
                  "transformation": "constant_propagation",        --常量优化
                  "resulting_condition": "((`test1`.`id` > 4999900) and multiple equal(`test1`.`id`, `test2`.`id`))"
                },
                {
                  "transformation": "trivial_condition_removal",   --琐碎的条件排除
                  "resulting_condition": "((`test1`.`id` > 4999900) and multiple equal(`test1`.`id`, `test2`.`id`))"
                }
              ]
            }
          },
          {
            "table_dependencies": [     --表依赖
              {
                "table": "`test1`",        --表名
                "row_may_be_null": false,  --是否有null值,flase是没有
                "map_bit": 0,
                "depends_on_map_bits": [
                ]
              },
              {
                "table": "`test2`",
                "row_may_be_null": false,
                "map_bit": 1,
                "depends_on_map_bits": [
                ]
              }
            ]
          },
          {
            "ref_optimizer_key_uses": [    --相关优化索引使用
              {
                "table": "`test1`",  
                "field": "id",             --索引字段
                "equals": "`test2`.`id`",  --连接的等值字段
                "null_rejecting": false
              },
              {
                "table": "`test2`",
                "field": "id",
                "equals": "`test1`.`id`",
                "null_rejecting": false
              }
            ]
          },
          {
            "rows_estimation": [          --行评估
              {
                "table": "`test1`",
                "range_analysis": {          --范围分析
                  "table_scan": {
                    "rows": 4804854,          --4804854行数据
                    "cost": 1.03e6            --花费1.03e6
                  },
                  "potential_range_indices": [   --可能的范围指数
                    {
                      "index": "PRIMARY",
                      "usable": true,           --可使用的索引
                      "key_parts": [
                        "id"
                      ]                         --可使用的索引字段
                    },
                    {
                      "index": "k_1",
                      "usable": false,         --不能使用的索引
                      "cause": "not_applicable"  --不被应用
                    }
                  ],
                  "setup_range_conditions": [     --设置范围条件
                  ],
                  "group_index_range": {          --组范围索引
                    "chosen": false,              --不选择的
                    "cause": "not_single_table"   --goup by不是一个表的,所以不选择
                  },
                  "analyzing_range_alternatives": {     --分析每个索引做范围扫描的花费
                    "range_scan_alternatives": [       --范围扫描花费
                      {
                        "index": "PRIMARY",
                        "ranges": [
                          "4999900 < id"
                        ],
                        "index_dives_for_eq_ranges": true,    --索引驱动等值范围扫描
                        "rowid_ordered": true,                --rowid是顺序的
                        "using_mrr": false,                   --不能使用mrr,因为是主键
                        "index_only": false,                  
                        "rows": 99,                           --过滤出来99行
                        "cost": 21.434,                       --花费21.434
                        "chosen": true                        --这个索引被选择选择
                      }
                    ],
                    "analyzing_roworder_intersect": {         --分析执行顺序阶段
                      "usable": false,                        --不可使用
                      "cause": "too_few_roworder_scans"       --少数的执行顺序扫描
                    }
                  },
                  "chosen_range_access_summary": {           --选择范围访问概述
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "PRIMARY",
                      "rows": 99,
                      "ranges": [
                        "4999900 < id"
                      ]
                    },
                    "rows_for_plan": 99,
                    "cost_for_plan": 21.434,
                    "chosen": true
                  }
                }
              },
              {
                "table": "`test2`",
                "range_analysis": {
                  "table_scan": {
                    "rows": 4804854,
                    "cost": 1.03e6
                  },
                  "potential_range_indices": [
                    {
                      "index": "PRIMARY",
                      "usable": true,
                      "key_parts": [
                        "id"
                      ]
                    },
                    {
                      "index": "k_2",
                      "usable": false,
                      "cause": "not_applicable"
                    }
                  ],
                  "setup_range_conditions": [
                  ],
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_single_table"
                  },
                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "PRIMARY",
                        "ranges": [
                          "4999900 < id"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": true,
                        "using_mrr": false,
                        "index_only": false,
                        "rows": 99,
                        "cost": 21.433,
                        "chosen": true
                      }
                    ],
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    }
                  },
                  "chosen_range_access_summary": {
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "PRIMARY",
                      "rows": 99,
                      "ranges": [
                        "4999900 < id"
                      ]
                    },
                    "rows_for_plan": 99,
                    "cost_for_plan": 21.433,
                    "chosen": true
                  }
                }
              }
            ]
          },
          {
            "considered_execution_plans": [   --决定执行计划
              {
                "plan_prefix": [             --计划前
                ],
                "table": "`test1`",          --test1表的执行计划
                "best_access_path": {        --最好的访问路径
                  "considered_access_paths": [  --决定的访问路径
                    {
                      "access_type": "ref",     --访问类型是ref
                      "index": "PRIMARY",       --使用的索引是主键
                      "usable": false,          
                      "chosen": false
                    },
                    {
                      "access_type": "range",
                      "rows": 99,
                      "cost": 41.234,
                      "chosen": true
                    }
                  ]
                },
                "cost_for_plan": 41.234,
                "rows_for_plan": 99,
                "rest_of_plan": [
                  {
                    "plan_prefix": [
                      "`test1`"
                    ],
                    "table": "`test2`",
                    "best_access_path": {
                      "considered_access_paths": [
                        {
                          "access_type": "ref",
                          "index": "PRIMARY",
                          "rows": 1,
                          "cost": 99.2,
                          "chosen": true
                        },
                        {
                          "access_type": "range",
                          "cause": "heuristic_index_cheaper",
                          "chosen": false
                        }
                      ]
                    },
                    "cost_for_plan": 160.03,
                    "rows_for_plan": 99,
                    "chosen": true
                  }
                ]
              },
              {
                "plan_prefix": [
                ],
                "table": "`test2`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "ref",
                      "index": "PRIMARY",
                      "usable": false,
                      "chosen": false
                    },
                    {
                      "access_type": "range",
                      "rows": 99,
                      "cost": 41.233,
                      "chosen": true
                    }
                  ]
                },
                "cost_for_plan": 41.233,
                "rows_for_plan": 99,
                "rest_of_plan": [
                  {
                    "plan_prefix": [
                      "`test2`"
                    ],
                    "table": "`test1`",
                    "best_access_path": {
                      "considered_access_paths": [
                        {
                          "access_type": "ref",
                          "index": "PRIMARY",
                          "rows": 1,
                          "cost": 99.2,
                          "chosen": true
                        },
                        {
                          "access_type": "range",
                          "cause": "heuristic_index_cheaper",
                          "chosen": false
                        }
                      ]
                    },
                    "cost_for_plan": 160.03,
                    "rows_for_plan": 99,
                    "pruned_by_cost": true
                  }
                ]
              }
            ]
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "((`test2`.`id` = `test1`.`id`) and (`test1`.`id` > 4999900))",
              "attached_conditions_computation": [
              ],
              "attached_conditions_summary": [
                {
                  "table": "`test1`",
                  "attached": "(`test1`.`id` > 4999900)"
                },
                {
                  "table": "`test2`",
                  "attached": null
                }
              ]
            }
          },
          {
            "refine_plan": [
              {
                "table": "`test1`",
                "access_type": "range"
              },
              {
                "table": "`test2`"
              }
            ]
          }
        ]
      }
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
}



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。