当前位置: 首页 > news >正文

mysql中optimizer trace的作用

大家好。对于MySQL 5.6以及之前的版本来说,查询优化器就像是一个黑盒子一样,我们只能通过EXPLAIN语句查看到最后 优化器决定使用的执行计划,却无法知道它为什么做这个决策。于是在MySQL5.6以及之后的版本中,MySQL新增了一个optimizer trace的功 能,这个功能可以让我们方便的查看优化器生成执行计划的整个过程,今天我们就来简单了解一下这个功能。

optimizer trace功能的开启与关闭由系统变量optimizer_trace决定,我们看一下:
在这里插入图片描述
可以看到enabled值为off ,表明这个功能默认是关闭的。 one_line的值是控制输出格式的,如果为on那么所有输出都将在一行中展示,不适合人阅读。

如果想打开optimizer trace功能,必须首先把enabled的值改为on ,我们可以通过下边这个sql语句修改enabled的值:

SET optimizer_trace="enabled=on";

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

QUERY : 表示我们的查询语句。

TRACE : 表示优化过程的JSON格式文本。

MISSING_BYTES_BEYOND_MAX_MEM_SIZE : 由于优化过程可能会输出很多,如果超过某个限制时,多余的文本将不会被显示,这个字段展示了被忽略的文本字节数。

INSUFFICIENT_PRIVILEGES : 表示是否没有权限查看优化过程,默认值是0。

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

#1. 打开optimizer trace功能 (默认情况下它是关闭的):

SET optimizer_trace="enabled=on";

#2. 输入自己的查询语句

SELECT ...;

#3. 从OPTIMIZER_TRACE表中查看上一个查询的优化过程

SELECT * FROM information_schema.OPTIMIZER_TRACE;

#4. 可能你还要观察其他语句执行的优化过程,重复上边的第2、3步。
#5. 当你停止查看语句的优化过程时,把optimizer trace功能关闭。

SET optimizer_trace="enabled=off"

下面我们以一个复杂一点的sql为例,来聊一聊如何使用optimizer trace功能。
在这里插入图片描述

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

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;

我们直接看一下通过查询OPTIMIZER_TRACE 表得到的输出:

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

通过上述的信息我们得知,优化过程大致分为了三个阶段:prepare 阶段optimize阶段execute阶段

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

好了,到这里我们就讲完了,大家有什么想法欢迎留言讨论。也希望大家能给作者点个关注,谢谢大家!最后依旧是请各位老板有钱的捧个人场,没钱的也捧个人场,谢谢各位老板!

相关文章:

mysql中optimizer trace的作用

大家好。对于MySQL 5.6以及之前的版本来说&#xff0c;查询优化器就像是一个黑盒子一样&#xff0c;我们只能通过EXPLAIN语句查看到最后 优化器决定使用的执行计划&#xff0c;却无法知道它为什么做这个决策。于是在MySQL5.6以及之后的版本中&#xff0c;MySQL新增了一个optimi…...

实习面试题(答案自敲)、

1、为什么要重写equals方法&#xff0c;为什么重写了equals方法后&#xff0c;就必须重写hashcode方法&#xff0c;为什么要有hashcode方法&#xff0c;你能介绍一下hashcode方法吗&#xff1f; equals方法默认是比较内存地址&#xff1b;为了实现内容比较&#xff0c;我们需要…...

二叉树讲解

目录 前言 二叉树的遍历 层序遍历 队列的代码 queuepush和queuepushbujia的区别 判断二叉树是否是完全二叉树 前序 中序 后序 功能展示 创建二叉树 初始化 销毁 简易功能介绍 二叉树节点个数 二叉树叶子节点个数 二叉树第k层节点个数 二叉树查找值为x的节点 判…...

Unity DOTS技术(五)Archetype,Chunk,NativeArray

文章目录 一.Chunk和Archetype什么是Chunk?什么是ArchType 二.Archetype创建1.创建实体2.创建并添加组件3.批量创建 三.多线程数组NativeArray 本次介绍的内容如下: 一.Chunk和Archetype 什么是Chunk? Chunk是一个空间,ECS系统会将相同类型的实体放在Chunk中.当一个Chunk…...

算法学习笔记(7.1)-贪心算法(分数背包问题)

##问题描述 给定 &#x1d45b; 个物品&#xff0c;第 &#x1d456; 个物品的重量为 &#x1d464;&#x1d454;&#x1d461;[&#x1d456;−1]、价值为 &#x1d463;&#x1d44e;&#x1d459;[&#x1d456;−1] &#xff0c;和一个容量为 &#x1d450;&#x1d44e;&…...

气膜建筑的施工对周边环境影响大吗?—轻空间

随着城市化进程的加快&#xff0c;建筑行业的快速发展也带来了环境问题。噪音、灰尘和建筑废料等对周边居民生活和生态环境造成了不小的影响。因此&#xff0c;选择一种环保高效的施工方式变得尤为重要。气膜建筑作为一种新兴的建筑形式&#xff0c;其施工过程对周边环境的影响…...

【计算机网络】对应用层HTTP协议的重点知识的总结

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…...

30分钟快速入门TCPDump

TCPDump是一款功能强大的网络分析工具&#xff0c;它可以帮助网络管理员捕获并分析流经网络接口的数据包。由于其在命令行环境中的高效性与灵活性&#xff0c;TCPDump成为了网络诊断与安全分析中不可或缺的工具。本文将详细介绍TCPDump的基本用法&#xff0c;并提供一些高级技巧…...

Python | 刷题日记

1.海伦公式求三角形的面积 area根号下&#xff08;p(p-a)(p-b&#xff09;(p-c)) p是周长的一半 2.随机生成一个整数 import random xrandom.randint(0,9)#随机生成0到9之间的一个数 yeval(input("please input:")) if xy:print("bingo") elif x<y:pri…...

“JS逆向 | Python爬虫 | 动态cookie如何破~”

案例目标 目标网址:aHR0cHMlM0EvL21hdGNoLnl1YW5yZW54dWUuY29tL21hdGNoLzI= 本题目标:提取全部 5 页发布日热度的值,计算所有值的加和,并提交答案 常规 JavaScript 逆向思路 JavaScript 逆向工程通常分为以下三步: 寻找入口:逆向工程的核心在于找出加密参数的生成方式。…...

十.数据链路层——MAC/ARP

IP和数据链路层之间的关系 引言 在IP一节中&#xff0c;我们说IP层路由(数据转发)的过程&#xff0c;就像我们跳一跳游戏一样&#xff0c;从一个节点&#xff0c;转发到另一个节点 它提供了一种将数据从A主机跨网络发到B主机的能力 什么叫做跨网络&#xff1f;&#xff1f;&a…...

Linux主机安全可视化运维(免费方案)

本文介绍如何使用免费的主机安全软件,在自有机房或企业网络实现对Linux系统进行可视化“主机安全”管理。 一、适用对象 本文适用于个人或企业内的Linux服务器运维场景,实现免费、高效、可视化的主机安全管理。提前发现主机存在的安全风险,全方位实时监控主机运行时入侵事…...

Vite + Vue 3 前端项目实战

一、项目创建 npm install -g create-vite #安装 Vite 项目的脚手架工具 # 或者使用yarn yarn global add create-vite#创建vite项目 create-vite my-vite-project二、常用Vue项目依赖安装 npm install unplugin-auto-import unplugin-vue-components[1] 安装按需自动导入组…...

python-字符替换

[题目描述] 给出一个字符串 s 和 q 次操作&#xff0c;每次操作将 s 中的某一个字符a全部替换成字符b&#xff0c;输出 q 次操作后的字符串输入 输入共 q2 行 第一行一个字符串 s 第二行一个正整数 q&#xff0c;表示操作次数 之后 q 行每行“a b”表示把 s 中所有的a替换成b输…...

团队项目开发使用git工作流(IDEA)【精细】

目录 开发项目总体使用git流程 图解流程 1.创建项目仓库[组长完成] 2. 创建项目&#xff0c;并进行绑定远程仓库【组长完成】 3.将项目与远程仓库&#xff08;gitee&#xff09;进行绑定 3.1 创建本地的git仓库 3.2 将项目添加到缓存区 3.3 将项目提交到本地仓库&#…...

爬虫案例实战

文章目录 一、窗口切换实战二、京东数据抓取 一、窗口切换实战 案例实战&#xff1a;使用selenium实现打开百度和腾讯两个窗口并切换 知识点&#xff1a;用到selenium中execute_script()执行js代码及switch_to.window()方法 全部代码如下&#xff1a; import time import war…...

uniapp uni-popup内容被隐藏问题

今天开发新需求的时候发现uni-popup 过一会就被隐藏掉只留下遮罩(css被更改了)&#xff0c;作者进行了如下调试。 1.讲uni-popup放入其他节点内 失败&#xff01; 2.在生成dom后在打开 失败&#xff01; 3.uni-popup将该节点在包裹一层 然后将统计设置样式&#xff0c;v-if v-s…...

leetcode155 最小栈

题目 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。i…...

在Ubuntu乌班图上安装Docker

最近在学习乌班图相关的内容&#xff0c;找了一些文档安装的都是报错的&#xff0c;于是记录一下学习过程&#xff0c;希望也能帮助有缘人&#xff0c;首先查看乌班图的系统版本&#xff0c;我的是如下的&#xff1a; cat /proc/version以下是在Ubuntu 20.04版本上安装Docker。…...

【Redis数据库百万字详解】数据持久化

文章目录 一、持久化1.1、什么是持久化1.2、持久化方式1.3、RDB优缺点1.4、AOF优缺点 二、RDB持久化触发机制2.1、手动触发2.2、自动触发 三、RDB持久化配置3.1、配置文件3.2、配置查询/设置3.3、禁用持久化3.4、RDB文件恢复 四、RDB持久化案例4.1、手动持久化4.2、自动持久化案…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...