Optimizer trance—mysql进阶(五十三)

2023-10-29

前面介绍了,如果加个format=JOSN会把数据以json的格式返回,如果想看查询的额外信息,还可以在explain之后加个show warning查看,其中如果code为1003,则代表message里的内容是mysql优化器优化之后的sql。

JSON格式执行计划(6)—mysql执行计划(五十二)

对于mysql5.6之前的版本说,mysql像黑盒子,只能通过explain语句查看最后优化器决定使用的执行计划,却无法知道他做什么决定。在mysql5.6之后,mysql设计为我们贴心的加了optimizer trance,这个功能方便我们执行优化器的过程,这个功能的开启和关闭由系统变量optimizer_trance决定。

mysql> show variables like 'optimizer_trace';

+-----------------+--------------------------+

| Variable_name   | Value                    |

+-----------------+--------------------------+

| optimizer_trace | enabled=off,one_line=off |

+-----------------+--------------------------+

1 row in set (0.01 sec)

这里可以看到系统变量默认是关闭的, 如果开启需要改成on。这里one_line表示在一行展示,我们默认就关闭,不然不方便我们观看。

mysql> SET optimizer_trace="enabled=on";

Query OK, 0 rows affected (0.00 sec)

当我们设置为on的时候,则会打开,当我们输入我们想看的sql语句查询之后,就可以看information_schema数据库下的optimizer_trace表中查看完整优化过程。

当我们查看之后,可以看到四个部分:

  1. Query:表示我们的查询语句。
  2. trace:表示优化过程的JSON格式文本。
  3. MISSING_BUTES_BEYOND_MAX_MEM_SIZE:由于优化过程可能输出很多,如果超过某个限制,多余文本将不会被显示,展示被忽略的文本字段。
  4. INSUFFICIENT_PRIVILEGS:表示是否没有权限查看优化过程,默认是0,只有某些特殊情况才是1。
SET optimizer_trace="enabled=on";

SELECT * FROM s1 WHERE 
    key1 > 'z' AND 
    key2 < 1000000 AND 
    key3 IN ('a', 'b', 'c') AND 
    common_field = 'abc';
    
SELECT * FROM information_schema.OPTIMIZER_TRACE\G    

之后就可以看到显示:

*************************** 1. row ***************************
# 分析的查询语句是什么
QUERY: SELECT * FROM s1 WHERE
    key1 > 'z' AND
    key2 < 1000000 AND
    key3 IN ('a', 'b', 'c') AND
    common_field = 'abc'

# 优化的具体过程
TRACE: {
  "steps": [
    {
      "join_preparation": {     # prepare阶段
        "select#": 1,
        "steps": [
          {
            "IN_uses_bisection": true
          },
          {
            "expanded_query": "/* select#1 */ select `s1`.`id` AS `id`,`s1`.`key1` AS `key1`,`s1`.`key2` AS `key2`,`s1`.`key3` AS `key3`,`s1`.`key_part1` AS `key_part1`,`s1`.`key_part2` AS `key_part2`,`s1`.`key_part3` AS `key_part3`,`s1`.`common_field` AS `common_field` from `s1` where ((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {    # optimize阶段
        "select#": 1,
        "steps": [
          {
            "condition_processing": {   # 处理搜索条件
              "condition": "WHERE",
              # 原始搜索条件
              "original_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))",
              "steps": [
                {
                  # 等值传递转换
                  "transformation": "equality_propagation",
                  "resulting_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))"
                },
                {
                  # 常量传递转换    
                  "transformation": "constant_propagation",
                  "resulting_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))"
                },
                {
                  # 去除没用的条件
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))"
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            # 替换虚拟生成列
            "substitute_generated_columns": {
            } /* substitute_generated_columns */
          },
          {
            # 表的依赖信息
            "table_dependencies": [
              {
                "table": "`s1`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "ref_optimizer_key_uses": [
            ] /* ref_optimizer_key_uses */
          },
          {
          
            # 预估不同单表访问方法的访问成本
            "rows_estimation": [
              {
                "table": "`s1`",
                "range_analysis": {
                  "table_scan": {   # 全表扫描的行数以及成本
                    "rows": 9688,
                    "cost": 2036.7
                  } /* table_scan */,
                  
                  # 分析可能使用的索引
                  "potential_range_indexes": [
                    {
                      "index": "PRIMARY",   # 主键不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_key2",  # idx_key2可能被使用
                      "usable": true,
                      "key_parts": [
                        "key2"
                      ] /* key_parts */
                    },
                    {
                      "index": "idx_key1",  # idx_key1可能被使用
                      "usable": true,
                      "key_parts": [
                        "key1",
                        "id"
                      ] /* key_parts */
                    },
                    {
                      "index": "idx_key3",  # idx_key3可能被使用
                      "usable": true,
                      "key_parts": [
                        "key3",
                        "id"
                      ] /* key_parts */
                    },
                    {
                      "index": "idx_key_part",  # idx_keypart不可用
                      "usable": false,
                      "cause": "not_applicable"
                    }
                  ] /* potential_range_indexes */,
                  "setup_range_conditions": [
                  ] /* setup_range_conditions */,
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  } /* group_index_range */,
                  
                  # 分析各种可能使用的索引的成本
                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        # 使用idx_key2的成本分析
                        "index": "idx_key2",
                        # 使用idx_key2的范围区间
                        "ranges": [
                          "NULL < key2 < 1000000"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,   # 是否使用index dive
                        "rowid_ordered": false,     # 使用该索引获取的记录是否按照主键排序
                        "using_mrr": false,     # 是否使用mrr
                        "index_only": false,    # 是否是索引覆盖访问
                        "rows": 12,     # 使用该索引获取的记录条数
                        "cost": 15.41,  # 使用该索引的成本
                        "chosen": true  # 是否选择该索引
                      },
                      {
                        # 使用idx_key1的成本分析
                        "index": "idx_key1",
                        # 使用idx_key1的范围区间
                        "ranges": [
                          "z < key1"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,   # 同上
                        "rowid_ordered": false,   # 同上
                        "using_mrr": false,   # 同上
                        "index_only": false,   # 同上
                        "rows": 266,   # 同上
                        "cost": 320.21,   # 同上
                        "chosen": false,   # 同上
                        "cause": "cost"   # 因为成本太大所以不选择该索引
                      },
                      {
                        # 使用idx_key3的成本分析
                        "index": "idx_key3",
                        # 使用idx_key3的范围区间
                        "ranges": [
                          "a <= key3 <= a",
                          "b <= key3 <= b",
                          "c <= key3 <= c"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,   # 同上
                        "rowid_ordered": false,   # 同上
                        "using_mrr": false,   # 同上
                        "index_only": false,   # 同上
                        "rows": 21,   # 同上
                        "cost": 28.21,   # 同上
                        "chosen": false,   # 同上
                        "cause": "cost"   # 同上
                      }
                    ] /* range_scan_alternatives */,
                    
                    # 分析使用索引合并的成本
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    } /* analyzing_roworder_intersect */
                  } /* analyzing_range_alternatives */,
                  
                  # 对于上述单表查询s1最优的访问方法
                  "chosen_range_access_summary": {
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "idx_key2",
                      "rows": 12,
                      "ranges": [
                        "NULL < key2 < 1000000"
                      ] /* ranges */
                    } /* range_access_plan */,
                    "rows_for_plan": 12,
                    "cost_for_plan": 15.41,
                    "chosen": true
                  } /* chosen_range_access_summary */
                } /* range_analysis */
              }
            ] /* rows_estimation */
          },
          {
            
            # 分析各种可能的执行计划
            #(对多表查询这可能有很多种不同的方案,单表查询的方案上边已经分析过了,直接选取idx_key2就好)
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`s1`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "rows_to_scan": 12,
                      "access_type": "range",
                      "range_details": {
                        "used_index": "idx_key2"
                      } /* range_details */,
                      "resulting_rows": 12,
                      "cost": 17.81,
                      "chosen": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "condition_filtering_pct": 100,
                "rows_for_plan": 12,
                "cost_for_plan": 17.81,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            # 尝试给查询添加一些其他的查询条件
            "attaching_conditions_to_tables": {
              "original_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`s1`",
                  "attached": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            # 再稍稍的改进一下执行计划
            "refine_plan": [
              {
                "table": "`s1`",
                "pushed_index_condition": "(`s1`.`key2` < 1000000)",
                "table_condition_attached": "((`s1`.`key1` > 'z') and (`s1`.`key3` in ('a','b','c')) and (`s1`.`common_field` = 'abc'))"
              }
            ] /* refine_plan */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {    # execute阶段
        "select#": 1,
        "steps": [
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}

# 因优化过程文本太多而丢弃的文本字节大小,值为0时表示并没有丢弃
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0

# 权限字段
INSUFFICIENT_PRIVILEGES: 0

1 row in set (0.00 sec)

优化器追踪主要有三个部分,prepare部分,optimize阶段,execute阶段,看名字都知道,我们要着重看optimize阶段。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Optimizer trance—mysql进阶(五十三) 的相关文章

  • MySQL 中的断言

    我有一个针对大型数据库运行的 SQL 脚本 我想在开始时提出几个简单的查询 作为健全性检查 有没有办法在MySQL中写断言 或者任何类型的 选择 如果它与该值不匹配 则中止整个脚本 一些疯狂的代码 要点是 SET可能会引发 mysql 变量
  • PDO fetch() 失败时会抛出异常吗?

    有没有方法PDO语句 fetch http php net manual en pdostatement fetch php如果 PDO 错误报告系统设置为抛出异常 则在失败时抛出异常 例如 如果我设置 PDO ATTR ERRMODE g
  • 在mysql中搜索“SanF”时获取旧金山的记录

    当我搜索 SanF 时获得 San Francisco 记录 SELECT FROM table WHERE col LIKE san Works SELECT FROM table WHERE col LIKE san F Works S
  • MySQL 触发器和 SUM()

    我有两张桌子 学生桌和家庭桌 在学生中 我有列 st venue 和total venue 家里我有收入 Total Revenue 是学生 st 收入与家庭收入之和 其中 family id student student id stud
  • 将列的值添加到 LIKE 语句中?

    我有 3 个标签表 标签类别和使用过的标签 我想要获取所有标签的列表以及已使用标签的计数 所使用标签的格式是每个具有标签的文档 ID 的逗号分隔值 我一直在尝试类似的方法 但无法将tags tag 字段的值插入到LIKE 语句中 SELEC
  • 从存储过程中的动态 SQL 获取结果

    我正在编写一个存储过程 需要在过程中动态构造 SQL 语句以引用传入的表名称 我需要让这个 SQL 语句返回一个结果 然后我可以在整个过程的其余部分中使用该结果 我尝试过使用临时表和所有内容 但我不断收到一条消息 提示我需要声明变量等 例如
  • MySQL“选择更新”行为

    根据 MySql 文档 MySql 支持多粒度锁定 MGL case 1 开放航站楼 1 连接到mysql mysql gt start transaction Query OK 0 rows affected 0 00 sec mysql
  • RMySQL fetch - 找不到继承的方法

    使用 RMySQL 我想将数据从数据库加载到 R 中的数据帧中 为此 我使用以下代码 R连接数据库 con lt dbConnect MySQL user root password password dbname prediction h
  • 物理写入文件已满 - mysql 错误

    我正在使用xampp 每次启动mysql时 我都会在xampp中收到以下错误 Error MySQL shutdown unexpectedly 13 16 14 mysql This may be due to a blocked por
  • SQL 大表中的随机行(使用 where 子句)

    我有一个网站 人们可以在其中对汽车进行投票 向用户展示 4 辆汽车 他 她可以投票选出他们最喜欢的汽车 桌子cars有重要的列 car id int 10 not auto increment so has gaps views int 7
  • SQL Server 查询结果集的大小

    SQL Server 中是否有确定结果集中 Mgmt Studio 查询中返回的数据大小 以 MEGS 为单位 您可以打开客户端统计信息 查询菜单 包括客户端统计信息 它给出执行查询时从服务器返回的字节数
  • SQL Server 使用通配符加入并在第一个匹配处停止

    IF OBJECT ID tempdb TABLE1 IS NOT NULL DROP TABLE TABLE1 IF OBJECT ID tempdb TABLE2 IS NOT NULL DROP TABLE TABLE2 CREATE
  • 如何在 join 语句中进行计数

    我有桌子post int post id varchar title text content和表comment int comment id int post id varchar content其中 post id 是外键引用表帖子 如
  • 我可以在一个查询中更新/选择表吗?

    我需要在查看页面时选择数据并更新 视图 列 有没有一种方法可以在一个查询中执行此操作 或者我是否必须使用不同的查询 如果您不想 不需要使用事务 则可以创建一个存储过程 该过程首先更新视图计数 然后选择值并将其返回给用户
  • SQL Server 转换选择一列并将其转换为字符串

    是否可以编写一条从表中选择列并将结果转换为字符串的语句 理想情况下 我希望有逗号分隔的值 例如 假设 SELECT 语句看起来像这样 SELECT column FROM table WHERE column lt 10 结果是一列包含值的
  • 如何在Sequelize中从主模型同一级别的包含模型返回结果?

    这是我在项目中完成的代码和结果 我想获得包含模型的结果与主模型相同的结果 下面的代码是我所做的 序列化查询 User findAll include model Position attributes POSITION NAME then
  • 如何通过循环变量在 dbt 中多次运行 SQL 模型?

    我有一个 dbt 模型 测试模型 接受地理变量 zip state region 在配置中 我想通过循环变量来运行模型三次 每次使用不同的变量运行它 问题是 我有一个如下所示的宏 它将变量附加到输出表名称的末尾 即运行测试模型 with z
  • 将多行合并为一行并根据行数附加列

    我正在尝试将同一个表的多行合并为一个 我有一个像这样的示例表 Col1 Col2 Col3 Col4 Col5 Col6 1 BH1 CB 12 CC CC Conveyor Mal 1 BH1 CB 104 ZC ZC Full Emp
  • 如何使用 PHP 获取列中的所有值?

    我一直在到处寻找这个问题 但仍然找不到解决方案 如何从 mySQL 列中获取所有值并将它们存储在数组中 例如 表名称 客户 列名称 ID 名称 行数 5 我想获取此表中所有 5 个名称的数组 我该如何去做呢 我正在使用 PHP 我试图 SE
  • 如何解决 MySQL innodb 在 TRUNCATE TABLE 上“等待表元数据锁”?

    在 GitLab CI 服务器中运行包含数百个应用程序单元测试的测试套件 运行 10 次测试后 不知怎的 它总是卡在等待 TRUNCATE TABLE 上的表元数据锁上 这是一个拆卸步骤 我知道SHOW ENGINE INNODB STAT

随机推荐

  • Rhythmbox中文乱码解决办法

    转自 http hi baidu com morgensonne item 3470aef58747abde6325d2d9 今天在网络上找到了一个比较好的解决Rhythmbox中文乱码的问题的方法 进入你的音乐文件夹执行如下代码 mid3
  • vue3项目(七)----Login

    1 登录 整体认识和路由配置 2 登录 表单校验实现 ElementPlus表单组件内置了表单校验功能 只需要按照组件要求配置必要参数即可 思想 当功能很复杂时 通过多个组件各自负责某个小功能 再组合成一个大功能是组件设计中的常用方法 表单
  • 使用vue-cli创建一个vue3项目

    1 安装脚手架vue cli 如果之前已经安装过vue cli 先查看版本 保证vue cli版本在4 5 0以上 vue V 如果版本低于4 5 0 执行以下命令升级 npm install g vue cli 安装过程中有可能会出现报错
  • 大疆TT无人机编程初体验,教你对拥抱开源的无人机为所欲为!

    先放个项目演示视频镇帖 可能是大疆TT无人机的第一款DIY遥控器 大疆TT无人机编程试飞初体验 认识我的朋友 大概都知道 我是一个 运气爆棚 的人 经常能 捡 到一些好玩的东西 这不 前两天在家门口 捡 到一架大疆 RoboMaster T
  • 有15个人围成一圈,顺序排号。从第一个人开始报数(从1~3报数),凡报到3的人退出圈子,问最后留下的人 C#版

    今天下午 某一同学 问我一面试题 第一做法就是度娘了半天 发现都是c c 的 遂参考逻辑 整理完一C 版本的 留个小纪念 绝对正宗C namespace ConsoleApplication1 class Program static vo
  • .Net C# 免费PDF合成软件

    最近用到pdf合成 发现各种软件均收费啊 这个技术非常简单 别人写好的库一大把 这里用到了PDFsharp 项目地址Home of PDFsharp and MigraDoc Foundation 软件下载地址 https download
  • 常用的 SQL Server 关键字及其含义

    SQL Server 是一种关系型数据库管理系统 RDBMS 提供了用于管理和操作数据库的各种关键字 以下是一些常用的 SQL Server 关键字及其含义 1 SELECT 用于从数据库中检索数据 2 INSERT 用于将新记录插入到数据
  • MATLAB 排列组合问题

    毕设ing 最近每天除了看论文就是matlab仿真 MATLAB编程强调 vectorization 对矩阵进行操作 毕竟人家名字就叫Mat Lab 矩阵的实验室 对于排列组合问题 按照C语言的思路肯定就用for循环 但是在matlab里
  • MAC-下载安装robotframework

    1 首先 先看自己的电脑有没有自带python which python gt usr bin python 2 查看当前python 版本 python version gt Python 2 7 10 default Oct 23 20
  • 以太坊源码(03):POA委员会选举机制

    目录 1 名词介绍 2 矿工投票方法 3 委员会确定投票流程 3 1 关键概念描述 3 1 1 Epoch checkpointInterval 3 1 2 Snapshot 3 2 投票方法 1 名词介绍 节点 普通的以太坊节点 没有区块
  • 1000 BASE-T1 PMA一致性测试解析

    车载以太网是为了满足汽车行业对高可靠性 低电磁辐射 低功耗 带宽分配 低延迟以及同步实时性等方面的要求而产生的 目前车载电子控制单元中 最常用的是1000BASE T1技术 其遵循的是IEEE 802 3bp标准规范要求 1000BASE
  • Nginx代理(Linux&Windows)-服务器

    Linux linux一般都是用宝塔面板 一键安装使用 下面是安装完后添加配置就可以指定文件目录了 注意好空格 宝塔阿里云开启端口 宝塔阿里云开启端口 宝塔阿里云开启端口 就okk了 Windows 直接下一个Nginx https pan
  • Angular 和 Flask 全栈简易演示

    对于 JavaScript 框架 MEAN 堆栈以其方式非常有名 我经常遇到项目要求 人们希望使用 Python 构建服务器代码 主要是因为它与物联网 图像处理 数学应用程序或语言选择有关 Django 是 Python 爱好者构建服务器端
  • qt在没有环境下如何运行exe 打包流程-亲测简介可用

    配图 文字流程叙述 0 最好使用release 生成的exe 进行打包 不然最后的文件会特别大几个G 用relese生成的exe打包几十MB 1 用release生成的exe单独复制一份 放入一个自定义的文件夹 2 打开qt编译器命令框 注
  • 计算机网络打不开怎么办,电脑网页打不开怎么回事

    电脑网页打不开怎么回事 电脑网页打不开怎么回事 电脑没有断开网络 却打不开网页 这是怎么回事呢 通常由于电脑的DNS解析出现问题 所以才会导致网页打不开 下面教大家电脑网页打不开怎么回事的解决办法 一 清除DNS解析缓存 关于电脑网页打不开
  • 详细分析vcoco2014HOI数据集

    vcoco images 图片 train2014 共82783张 COCO train2014 000000581921 jpg COCO train2014 000000581922 jpg COCO train2014 0000005
  • 记录ubuntu启动卡在logo界面有鼠标进不了桌面的经历,以及安装ubuntu踩的坑

    出现问题前 我之前安装过很多次ubuntu 不管是虚拟机 4 5次 还是双系统 3 4次 每次都是我自己搞崩的 就是我和之前一样开始安装搜狗输入法 之前没出过问题 然后就是这次安装完 我感觉和之前不一样 就是之前不知道为什么安装完会有pin
  • 波兰表达式 - 前,中,后缀表达式计算转换

    先看一个算术题 3 4 5 6 29 前缀表达式 3456 中缀表达式 3 4 5 6 你会算的 后缀表达式 34 5 6 利用栈的特性来运算表达式 当前我只拿到了 3 4 5 6 让我求它的前缀和后缀 求后缀口诀 1 从左到右看 数字忙显
  • ubuntu 提示 Could not get lock /var/lib/dpkg/lock-frontend.的处理办法

    今天可能操作删除某个程序的时候提示无法删除 给锁定了 一直显示 Waiting for cache lock Could not get lock var lib dpkg lock frontend It is held by proce
  • Optimizer trance—mysql进阶(五十三)

    前面介绍了 如果加个format JOSN会把数据以json的格式返回 如果想看查询的额外信息 还可以在explain之后加个show warning查看 其中如果code为1003 则代表message里的内容是mysql优化器优化之后的