技术分享 | 一文了解 MySQL Optimizer Trace 的神奇功效

news2024/11/23 0:20:37

作者:Mutlis

CSDN & 阿里云 & 知乎 等平台优质作者,擅长Oracle & MySQL等主流数据库系统的维护和管理等

本文来源:原创投稿

前言

对于 MySQL 5.6 以及之前的版本来说,查询优化器就像是一个黑盒子一样,你只能通过 EXPLAIN 语句查看到最后优化器决定使用的执行计划,却无法知道它为什么做这个决策。这对于一部分喜欢刨根问底的⼩伙伴来说简直是灾难:“我就觉得使用其他的执行方案⽐ EXPLAIN 输出的这种方案强,凭什么优化器做的决定和我想的不一样呢?”这篇文章主要介绍使用 optimizer trace 查看优化器生成执行计划的整个过程。

optimizer trace 表的神奇功效

在 MySQL 5.6 以及之后的版本中,设计 MySQL 的大叔贴⼼的为这部分小伙伴提出了一个 optimizer trace 的功能,这个功能可以让我们方便的查看优化器生成执行计划的整个过程,这个功能的开启与关闭由系统变量 optimizer_trace 决定,我们看一下:

mysql> show variables like 'optimizer_trace';
+-----------------+--------------------------+
| Variable_name   | Value                    |
+-----------------+--------------------------+
| optimizer_trace | enabled=off,one_line=off |
+-----------------+--------------------------+
1 row in set (0.01 sec)

可以看到 enabled 值为 off,表明这个功能默认是关闭的。

小提示:

one_line 的值是控制输出格式的,如果为 on 那么所有输出都将在一行中展示,不适合⼈阅读,所以我们就保持其默认值为 off 吧。

如果想打开这个功能,必须⾸先把 enabled 的值改为 on,就像这样:

mysql> SET optimizer_trace="enabled=on";
Query OK, 0 rows affected (0.00 sec)

然后我们就可以输入我们想要查看优化过程的查询语句,当该查询语句执行完成后,就可以到 information_schema 数据库下的 OPTIMIZER_TRACE 表中查看完整的优化过程。这个 OPTIMIZER_TRACE 表有 4 个列,分别是:

  • QUERY:表示我们查询的语句;
  • TRACE:表示优化过程的 JSON 格式⽂本;
  • MISSING_BYTES_BEYOND_MAX_MEM_SIZE:由于优化过程可能会输出很多,如果超过某个限制时,多余的⽂本将不会被显示,这个字段展示了被忽略的⽂本字节数;
  • INSUFFICIENT_PRIVILEGES:表示是否没有权限查看优化过程,默认值是 0,只有某些特殊情况下才会是 1,我们暂时不关心这个字段的值。

完整的使用 optimizer trace 功能的步骤总结如下:

步骤一: 打开 optimizer trace 功能 (默认情况下它是关闭的)。

mysql> SET optimizer_trace="enabled=on";
Query OK, 0 rows affected (0.01 sec)

步骤二: 输入查询语句。

SELECT	...;

步骤三:optimizer_trace 表中查看上一个查询的优化过程。

SELECT * FROM information_schema.OPTIMIZER_TRACE;

步骤四: 可能你还要观察其他语句执行的优化过程,重复上边的第 2、3步。

步骤五: 当你停⽌查看语句的优化过程时,把 optimizer trace 功能关闭。

mysql> SET optimizer_trace="enabled=off";
Query OK, 0 rows affected (0.01 sec)

现在我们有一个搜索条件比较多的查询语句,它的执行计划如下:

mysql> EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND  key2 < 1000000 AND key3 IN ('aa', 'bb', 'cb') AND   common_field = 'abc';
+----+-------------+-------+------------+-------+----------------------------+----------+---------+------+------+----------+------------------------------------+
| id | select_type | table | partitions | type  | possible_keys              | key      | key_len | ref  | rows | filtered | Extra                              |
+----+-------------+-------+------------+-------+----------------------------+----------+---------+------+------+----------+------------------------------------+
|  1 | SIMPLE      | s1    | NULL       | range | idx_key2,idx_key1,idx_key3 | idx_key1 | 403     | NULL |    1 |     5.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+----------------------------+----------+---------+------+------+----------+------------------------------------+
1 row in set, 1 warning (0.00 sec)

可以看到该查询可能使用到的索引有3个,那么为什么优化器最终选择了idx_key1而不选择其他的索引或者直接全表扫描呢?这时候就可以通过otpimzer trace 功能来查看优化器的具体工作过程:

mysql> SET optimizer_trace="enabled=on";
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM s1 WHERE key1 > 'z' AND  key2 < 1000000 AND key3 IN ('aa', 'bb', 'cb') AND   common_field = 'abc';
Empty set (0.00 sec)

mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE\G   

MySQL 可能会在之后的版本中添加更多的优化过程信息。不过杂乱之中其实还是蛮有规律的,优化过程大致分为了三个阶段:

  • prepare 阶段
  • optimize 阶段
  • execute 阶段

我们所说的基于成本的优化主要集中在 optimize 阶段,对于单表查询来说,我们主要关注 optimize 阶段的 "rows_estimation" 这个过程。这个过程深入分析了对单表查询的各种执行方案的成本,对于多表连接查询来说,我们更多需要关注 "considered_execution_plans" 这个过程,这个过程里会写明各种不同的连接方式所对应的成本。反正优化器最终会选择成本最低的那种方案来作为最终的执行计划,也就是我们使用 EXPLAIN 语句所展现出的那种方案。

最后,我们为感兴趣的小伙伴展示一下通过查询 OPTIMIZER_TRACE 表得到的输出(我使用#后跟随注释的形式为大家解释了优化过程中的一些比较重要的点,建议用电脑屏幕观看):

*************************** 1. row ***************************
# 分析的查询语句是什么
QUERY: SELECT * FROM s1 WHERE key1 > 'z' AND  key2 < 1000000 AND key3 IN ('aa', 'bb', 'cb') 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 ('aa','bb','cb')) and (`s1`.`common_field` = 'abc'))"
          }
        ]
      }
    },
    {
      "join_optimization": {  # optimize阶段
        "select#": 1,
        "steps": [
          {
            "condition_processing": { # 处理搜索条件
              "condition": "WHERE",
              # 原始搜索条件
              "original_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')) and (`s1`.`common_field` = 'abc'))",
              "steps": [
                {
                # 等值传递转换
                  "transformation": "equality_propagation",
                  "resulting_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')) and multiple equal('abc', `s1`.`common_field`))"
                },
                {
                # 常量传递转换
                  "transformation": "constant_propagation",
                  "resulting_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')) and multiple equal('abc', `s1`.`common_field`))"
                },
                {
                # 去除没用的条件
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "((`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')) and multiple equal('abc', `s1`.`common_field`))"
                }
              ]
            }
          },
          {
          # 替换虚拟生成列
            "substitute_generated_columns": {
            }
          },
          {
          # 表的依赖信息
            "table_dependencies": [
              {
                "table": "`s1`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ]
              }
            ]
          },
          {
            "ref_optimizer_key_uses": [
            ]
          },
          {
          # 预估不同单表访问方法的访问成本
            "rows_estimation": [
              {
                "table": "`s1`",
                "range_analysis": {
                  "table_scan": {
                    "rows": 20250,
                    "cost": 2051.35
                  },
                   # 分析可能使用的索引
                  "potential_range_indexes": [
                    {
                      "index": "PRIMARY", # 主键不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_key2",# idx_key2可能被使用
                      "usable": true,
                      "key_parts": [
                        "key2"
                      ]
                    },
                    {
                      "index": "idx_key1", # idx_key1可能被使用
                      "usable": true,
                      "key_parts": [
                        "key1",
                        "id"
                      ]
                    },
                    {
                      "index": "idx_key3", # idx_key3可能被使用
                      "usable": true,
                      "key_parts": [
                        "key3",
                        "id"
                      ]
                    },
                    {
                      "index": "idx_key_part", # idx_key_part不可用
                      "usable": false,
                      "cause": "not_applicable"
                    }
                  ],
                  "setup_range_conditions": [
                  ],
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  },
                  "skip_scan_range": {
                    "potential_skip_scan_indexes": [
                      {
                        "index": "idx_key2",
                        "usable": false,
                        "cause": "query_references_nonkey_column"
                      },
                      {
                        "index": "idx_key1",
                        "usable": false,
                        "cause": "query_references_nonkey_column"
                      },
                      {
                        "index": "idx_key3",
                        "usable": false,
                        "cause": "query_references_nonkey_column"
                      }
                    ]
                  },
                  # 分析各种可能使用的索引的成本
                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                      # 使用idx_key2的成本分析
                        "index": "idx_key2",
                        # 使用idx_key2的范围区间
                        "ranges": [
                          "NULL < key2 < 1000000"
                        ],
                        "index_dives_for_eq_ranges": true,# 是否使用index dive
                        "rowid_ordered": false,# 使用该索引获取的记录是否按照主键排序
                        "using_mrr": false, # 是否使用mrr
                        "index_only": false, # 是否是索引覆盖访问
                        "in_memory": 1,
                        "rows": 10125,# 使用该索引获取的记录条数
                        "cost": 3544.01,# 使用该索引的成本
                        "chosen": false,  # 使用该索引的成本
                        "cause": "cost" # 因为成本太大所以不选择该索引
                      },
                      {
                      # 使用idx_key1的成本分析
                        "index": "idx_key1",
                         # 使用idx_key1的范围区间
                        "ranges": [
                          "'z' < key1"
                        ],
                        "index_dives_for_eq_ranges": true,# 同上
                        "rowid_ordered": false,# 同上
                        "using_mrr": false,# 同上
                        "index_only": false,# 同上
                        "in_memory": 1,
                        "rows": 1,# 同上
                        "cost": 0.61,# 同上
                        "chosen": true# 是否选择该索引
                      },
                      {
                       # 使用idx_key3的成本分析
                        "index": "idx_key3",
                          # 使用idx_key3的范围区间
                        "ranges": [
                          "key3 = 'aa'",
                          "key3 = 'bb'",
                          "key3 = 'cb'"
                        ],
                        "index_dives_for_eq_ranges": true,# 同上
                        "rowid_ordered": false,# 同上
                        "using_mrr": false,# 同上
                        "index_only": false,# 同上
                        "in_memory": 1,
                        "rows": 3,# 同上
                        "cost": 1.81,# 同上
                        "chosen": false,# 同上
                        "cause": "cost"# 同上
                      }
                    ],
                    # 分析使用索引合并的成本
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    }
                  },
                  # 对于上述单表查询s1最优的访问方法
                  "chosen_range_access_summary": {
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "idx_key1",
                      "rows": 1,
                      "ranges": [
                        "'z' < key1"
                      ]
                    },
                    "rows_for_plan": 1,
                    "cost_for_plan": 0.61,
                    "chosen": true
                  }
                }
              }
            ]
          },
          {
          
            # 分析各种可能的执行计划
            #(对多表查询这可能有很多种不同的方案,单表查询的方案上边已经分析过了,直接选取idx_key1就好)
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ],
                "table": "`s1`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "rows_to_scan": 1,
                      "access_type": "range",
                      "range_details": {
                        "used_index": "idx_key1"
                      },
                      "resulting_rows": 1,
                      "cost": 0.71,
                      "chosen": true
                    }
                  ]
                },
                "condition_filtering_pct": 100,
                "rows_for_plan": 1,
                "cost_for_plan": 0.71,
                "chosen": true
              }
            ]
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "((`s1`.`common_field` = 'abc') and (`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')))",
              "attached_conditions_computation": [
              ],
              "attached_conditions_summary": [
                {
                  "table": "`s1`",
                  "attached": "((`s1`.`common_field` = 'abc') and (`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')))"
                }
              ]
            }
          },
          {
          # 尝试给查询添加一些其他的查询条件
            "finalizing_table_conditions": [
              {
                "table": "`s1`",
                "original_table_condition": "((`s1`.`common_field` = 'abc') and (`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')))",
                "final_table_condition   ": "((`s1`.`common_field` = 'abc') and (`s1`.`key1` > 'z') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')))"
              }
            ]
          },
          {
           # 再稍稍的改进一下执行计划
            "refine_plan": [
              {
                "table": "`s1`",
                "pushed_index_condition": "(`s1`.`key1` > 'z')",
                "table_condition_attached": "((`s1`.`common_field` = 'abc') and (`s1`.`key2` < 1000000) and (`s1`.`key3` in ('aa','bb','cb')))"
              }
            ]
          }
        ]
      }
    },
    {
      "join_execution": { # execute阶段
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
}
# 因优化过程文本太多而丢弃的文本字节大小,值为0时表示并没有丢弃
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
# 权限字段
INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.01 sec)

ERROR: 
No query specified

大家看到这个输出的第一感觉就是这文本也太多了点吧,其实这只是优化器执行过程中的一小部分。

如果有小伙伴对使用 EXPLAIN 语句展示出的对某个查询的执行计划很不理解,大家可以尝试使用 optimizer trace 功能来详细了解每一种执行方案对应的成本,相信这个功能能让大家更深入的了解 MySQL 查询优化器。

关于 SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs-cn/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs-cn/3.modules/3.7_auditplugin/auditplugin_development.html

提交有效 pr,高质量 issue,将获赠面值 200-500 元(具体面额依据质量而定)京东卡以及爱可生开源社区精美周边!更多关于 SQLE 的信息和交流,请加入官方QQ交流群:637150065
图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/589352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

迪赛智慧数——柱状图(基本柱状图):购买雪糕考虑的因素

效果图 冰淇淋季节来袭&#xff0c;因其细腻凉爽的口感和浓郁的口味被广大消费者所钟爱&#xff0c;近年来已经从一款传统的解暑冷冻饮品转变为一种原料丰富、口味多元、追求健康、愉悦和高品质生活方式的休闲食品。据数据显示&#xff0c;82.2&#xff05;女性、82.3%男性消费…

chatgpt赋能python:Python中乘方的介绍

Python中乘方的介绍 在Python中&#xff0c;乘方运算指数运算&#xff0c;常用符号为“”&#xff08;例如2的3次方为23&#xff09;。使用乘方运算可以快速地进行数值计算&#xff0c;尤其是在科学和工程领域中。 为什么要使用乘方运算&#xff1f; 乘方运算主要用于处理大…

NeRF算法

Instant-ngp Instant-ngp简单介绍 Instant-ngp论文链接 英伟达实现的github链接 taichi实现Instant-ngp taichi实现的github链接 渲染 采用体素渲染方法&#xff0c;从相机光线出发&#xff0c;逐步采样3D场景中的三维坐标点的颜色&#xff0c;即可渲染出3D画面。如果直接将3…

进阶神册,Redis+Nginx+设计模式+Spring全家桶+Dubbo核心技术笔记

最近花了很长的时间去搜罗Java核心技术好文&#xff0c;我把每个Java核心技术的优选文章都整理成了一个又一个的文档。昨天也是终于全部整理好了&#xff0c;今天就把这些东西分享给老铁们&#xff0c;也能为老铁们省去不少麻烦&#xff0c;想学什么技能了&#xff0c;遇到哪方…

vue3组件通信详解

vue3组件通信方式有以下几种&#xff1a;porps&#xff0c;$emit&#xff0c; bus&#xff0c;v-model&#xff0c;useAttrs&#xff0c;$ref/$parent&#xff0c;provide/inject&#xff0c;pinia&#xff0c;slot。下面将逐一讲解。 目录 1.porps&#xff1a;实现父子组件通…

V7.0_增加消息队列功能

一&#xff0c;功能描述 增加消息队列&#xff1b;使用自定义copy功能时&#xff0c;子进程copy结束后向父进程发送消息&#xff08;通过消息队列&#xff09;然后exit&#xff1b;此时因wait&#xff08;&#xff09;而处于阻塞态的父进程终于解除了阻塞并且从队列中读取到消…

【云原生-K8s-1】kubeadm搭建k8s集群(一主两从)完整教程及kubernetes简介

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; 文章目录 Kubernetes简介1 kubernetes架构1.1m…

清凉一夏小风扇-React版

这里写目录标题 前言 一、效果二、代码分享三、总结 前言 本片文章主要是做一个小练习&#xff0c;通过react来制作一个风扇练习css动画。 vue3实现部分看这里–> 一、效果 二、代码分享 1、主体框架 “react”: “^18.2.0” “sass”: “^1.62.1” 2、主要技术点 使用事…

企业上云容灾如何实现碳中和?

随着能源成本的增加和数据消费的激增&#xff0c;“电耗”和“碳排放”成为今年世界移动通信大会热议的话题。目前&#xff0c;ICT行业耗电量约占全球用电量的7%。预计到2040年&#xff0c;ICT行业碳排放量占全球排放量的比例将上升至14%。 容灾是企业为了在灾难时保证业务继续…

基于html+css的图展示99

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

Log4j2 - JNDI 注入漏洞复现(CVE-2021-44228)

文章目录 Apache Log4j简介漏洞介绍影响版本漏洞编号影响组件应用 环境准备靶场搭建漏洞利用利用工具使用方式 反弹shell操作 漏洞修复建议 Apache Log4j简介 Apache log4j 是 Apache 的一个开源项目&#xff0c; Apache log4j2 是一个 Java 的日志记录工具。该工具重写了 log4…

03.hadoop上课笔记之hdfs环境的搭建和使用

1.启动网络 在windows任务管理器启动服务vm Dhcp #由动态ip变为静态 #启动网卡ifup ens33#修改网卡配置文件vi /etc/sysconfig/network-scripts/ifcfg-ens33BOOTSTRAPstaticIPADDR192.168.202.101NETMASK255.255.255.0GATEWAY192.168.202.2DNS1192.168.202.2#重启网络 servic…

Vue动态路由在实际项目中的应用(包含前后台细节)

背景 近期做一个公司的门户网站&#xff0c;在产品和新闻这一块需要用到动态路由。本节博客以产品板块为例说一下动态路由的应用。 另外如果路由相关的基础知识有问题&#xff0c;可以查看我的这篇博客&#xff1a; Vue2路由的详细讲解 另外&#xff0c;这篇博客也会涉及到一…

macOS visual studio code 没有读写权限 检查更新报错

问题描述 visual studio code 检查更新&#xff0c;报错&#xff0c;visual studio code没有磁盘读写权限。&#xff08;可能会导致插件安装报错&#xff1f;&#xff09; 报错&#xff1a;The application is on a read-only volume. Please move the application and try a…

网络安全人员需要考的几本(含金量高)的证书!

网络安全行业含金量最高的当属CISSP——注册信息系统安全专家。但这个认证也是大家公认比较难考的证书. 含金量次之的CISP——国家注册信息安全专业人员&#xff0c;包含CISE&#xff08;工程师&#xff09;、CISO&#xff08;管理&#xff09;、CISA&#xff08;外审&#xf…

面试前15天刷完这个笔记,拿下字节测开岗offer....

面试&#xff0c;跳槽&#xff0c;每天都在发生&#xff0c;跳槽&#xff0c;更是很常见的&#xff0c;对于每个人来说&#xff0c;跳槽的意义也各不相同&#xff0c;可能是一个人更向往一个更大的平台&#xff0c;更好的地方&#xff0c;可以通过换一个环境改变自己的现状。而…

基于OpenCV [c++]——形态学操作(分析和应用)

摘要&#xff1a; 形态学一般指生物学中研究动物和植物结构的一个分支。用数学形态学&#xff08;也称图像代数&#xff09;表示以形态为基础对图像进行分析的数学工具。 基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的。 形…

这篇文章把MOS管的基础知识讲透了

MOS管&#xff08;Metal-Oxide-Semiconductor field-effect transistor&#xff09;是一种常见的半导体器件&#xff0c;它在数字电路、模拟电路、功率电子等领域都有广泛的应用。本文将从MOS管的基本结构、工作原理、参数特性等方面讲解MOS管的基础知识。 一、MOS管的基本结构…

MediaPlayer error(-38, 0) 异常处理

文章目录 1、参考资料2、业务背景3、解决方案 1、参考资料 Media Player called in state 0, error (-38,0) MediaPlayer的使用 2、业务背景 对时长超过 5s 的音频提供裁剪、试听功能&#xff0c;裁剪、试听最大时长均为 5s。当视频长度在 5s ~ 6s 之间&#xff0c;试听暂停…

Flink on yarn任务日志怎么看

1、jobmanager日志 在yarn上可以直接看 2、taskmanager日志 在flink的webui中可以看&#xff0c;但是flink任务失败后&#xff0c;webui就不存在了&#xff0c;那怎么看&#xff1f; 这是jobmanager的地址 hadoop02:19888/jobhistory/logs/hadoop02:45454/container_e03_16844…