MySQL内部临时表(Using temporary)案例详解及优化解决方法

目录

前言

一.场景案例

二、什么是内部临时表?

三、哪些场景会使用内部临时表?

四、内部临时表如何存储?

1)使用内存

2)先使用内存,再转化成磁盘文件

3)直接使用磁盘文件

五、如何优化内部临时表?

1.内部临时表通用的优化方向:

2.Union优化方向:

3.Group By优化方向:

开始的案例看下如何优化

1.使用索引优化group by

2.优化临时表内存配置参数

六、总结


前言

在之前的文章《一条SQL使用order by,引发IO问题》中,针对Using Filesort我们探讨了MySQL的排序策略与优化方向,今天,我们将介绍另一种会导致慢SQL的常见情况,即“Using temporary”,本文我们将带领大家详细探讨此类问题的原因及如何优化。

一.场景案例

在介绍具体内容之前,我们先来看个模拟的案例:

device表(id,device_name,device_type,time)有10万条数据,device_type有50种,device_name有5万种,这两个字段均没有索引

分别按照device_name与device_type进行group by,两类SQL施加相同的并发压力进行观察。

select device_name,count(*) as c from device group by device_name  limit 0,5;
select device_type,count(*) as c from device group by device_type  limit 0,5;

图片

图片

如上图所示可以观察到几个特点:

  • 两类SQL总QPS虽然只有10,但是却将CPU打满,影响到整个实例的性能

  • group by device_name执行时间达到了5秒,性能堪忧

  • CPU打满的根因归到了group by device_name

  • group by device_name比group by device_type多出了绿色代表的converting HEAP to MySIAM事件(5.7开始是converting HEAP to ondisk),而且所占比重不小

  • 两者执行计划相同,都是全表扫描,扫描行数相同,EXTRA字段都是Using temporary; Using filesort

看到这里有些新手同学可能会有些疑问:

  • 扫描行数一样,执行计划一样,为什么group by device_name要慢很多?

  • 多出的converting HEAP to MySIAM是什么意思?

  • Using temporary代表什么含义?

  • 如何优化此类问题?

接下来将通过介绍Using temporary内部临时表相关机制来解答这些问题。

二、什么是内部临时表?

要了解内部临时表,需要先知道临时表,临时表是一种会话级别的数据库对象,它只存在于创建它的数据库连接活动期间。与常规的持久化表不同,临时表在连接关闭或服务器重启后自动消失。MySQL临时表从创建方式上可以分为两种:

  • 外部临时表:用户通过显式的命令执行create temporary table创建的临时表。

  • 内部临时表:与外部临时表对应,并不是用户使用显示命令创建的临时表,而是数据库优化器为了协助复杂SQL的执行而自行创建的临时表,用户可以通过explain命令,在Extra列中,看是否有Using temporary,如果有就是用了内部临时表。

三、哪些场景会使用内部临时表?

该类场景大多是需要进行聚合操作,MySQL使用临时表存储聚合数据,以下场景可能使用内部临时表,具体还需查看执行计划确认。

  • UNION

  • Group BY

  • 使用TEMPTABLE算法、UNION查询、聚合的视图

  • 表连接中ORDER BY的列不在驱动表中的

  • DISTINCT查询并且加上ORDER BY

  • SQL中用到SQL_SMALL_RESULT修饰时

  • 复杂的派生表等

四、内部临时表如何存储?

有同学可能会问MySQL的内部临时表是存放在内存还是磁盘?其实都有可能,总共有三种存储方式

1)使用内存

需要存储数据量不超过配置项tmp_table_size与max_heap_table_size的值。

2)先使用内存,再转化成磁盘文件

当内存无法满足内部临时表存储的数据量时,MySQL会将临时表从内存转到磁盘文件,如果临时数据量庞大可能会导致磁盘容量的异常占用。

下图是group by device_name的toptimizer_trace路径:

  • MySQL先创建了内存的临时表,其location为memory (heap)

  • 然后发现内存不够用,又将数据转到了磁盘,location变成了disk(MyISAM/InnoDB),即通过特定引擎存储到磁盘文件表,此处默认引擎类型不同版本间有差异

  • 另外通过row_limit_estimate可以知道当前内存临时表可存放的行数

3)直接使用磁盘文件

使用SQL_BIG_RESULT 的修饰时会直接使用磁盘文件;另一种是临时表字段中存在 BLOB 或 TEXT 列时也会直接放弃使用内存临时表。

那我们平时针对临时表问题,如何进行监控与评估?

监控指标主要关注两个全局status:

  • created_tmp_tables :每创建一个临时表时会累加1。

  • created_tmp_disk_tables:每一次由内存临时表转为磁盘临时表时会累加1。

评估方式:created_tmp_disk_tables/ created_tmp_tables 比值越大说明磁盘临时表的占比越高,性能越差。

五、如何优化内部临时表?

1.内部临时表通用的优化方向:

  • 减少查询不必要的字段:减小临时表单行数据大小,进而提升内存临时表可存放的数据行数。

  • 调大临时表内存参数:修改系统变量 tmp_table_size 和 max_heap_table_size 的值,让临时表可以使用更多的内存。此处不能盲目调整,需要评估根因SQL使用临时表实际需要的内存大小(row_length*行数),如果略微上调参数即可满足临时表数据量要求可以选择调参验证,如果需要的内存与现有配置相差较大,则需要评估服务器整体内存使用情况,避免OOM。

  • 强制直接使用磁盘临时表:如果临时表的数据不可避免的会很大,可以考虑直接使用磁盘内部临时表,省掉内存临时表转换为磁盘临时表的过程。

2.Union优化方向:

考虑是否需要去重,如果不需要的话可以使用Union ALL代替Union,避免使用内部临时表。

3.Group By优化方向:

  • MySQL8.0之前GroupBy会附带排序,如果没有排序要求可以添加order by null。

  • 借助索引进行Group by聚合操作,可以避免使用内部临时表。

我们再回到开始的案例看下如何优化

1.使用索引优化group by

案例SQL是一个简单的Group BY语句,最直接的优化方式是添加索引,让MySQL利用B+树索引的有序性来加速聚合计算。

alter table device add index idx_name(device_name);

图片

添加索引后的执行计划

可以看到不再全表扫描,而是使用索引,同时EXTRA字段不再是Using temporary; Using filesort,SQL执行时间也回到ms级别。

添加索引后的性能表现

cpu使用率从99%降低到了10%以下,SQL执行时间变成了1秒以内,不再有converting HEAP to MySIAM/desk 事件。

2.优化临时表内存配置参数

并不是所有场景都能很好的使用索引,有些同学会关注不使用索引的情况下如何优化参数,我们依然拿开始的案例来分析参数调优。

我们回顾下上面慢SQL的optimizer_trace,MySQL默认tmp_table_size和max_heap_table_size是的16MB,从打印的trace可知临时表每行411字节共能存放40820行数据;而前面提到device表里device_name的种类是5万种,如果全用内存的话需要411*50000≈19.6MB。

那我们将临时表内存配置参数调整到20M再看下效果:

调大临时表参数后的optimizer_trace

可以发现调整后针对group by device_name语句可以存放51025条数据,不再需要磁盘临时表。

我们来观察下相同压力调整参数后的效果:cpu使用率从99%降低到了25%以下,SQL执行时间变成了1秒以内,不再有converting HEAP to MySIAM/desk 事件,性能提升效果5倍以上

图片

调大临时表参数后的性能表现

六、总结

内部临时表是MySQL用来辅助复杂SQL聚合计算使用的,会优先占用内存。可用内存大小受会话级参数 tmp_table_size 和 max_heap_table_size同时限制,内存不够时会将内存临时表转化为磁盘临时表,也可以通过SQL_SMALL_RESULT修饰来强制只使用磁盘临时表。

常用的优化方式有调整内存参数、大数据量时强制只使用磁盘临时表、Group By等SQL借助索引进行聚合、使用Union ALL替代UNion等。大家可以检查一下业务SQL临时表是否合理,给SQL提提速。

*************************************************************************************************************

实用小工具分享~

本文中我们使用的性能诊断工具是DBdoctor,有SQL性能审核、实例巡检、根因诊断、锁分析等功能,目前可永久免费使用,可关注DBdoctor官网(www.dbdoctor.cn)了解更多详细信息。一键安装包下载链接如下:

https://jhktob.oss-cn-beijing.aliyuncs.com/DBdoctorV3.2.3_20240820_x86.tar.gz

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

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

相关文章

【软件文档】项目总结报告编制模板(Word原件参考)

1. 项目概要 1.1. 项目基本信息 1.2. 项目期间 1.3. 项目成果 1.4. 开发工具和环境 2. 项目工作分析 2.1. 项目需求变更 2.2. 项目计划与进度实施 2.3. 项目总投入情况 2.4. 项目总收益情况 2.5. 项目质量情况 2.6. 风险管理实施情况 3. 经验与教训 3.1. 经验总结…

【异常错误】pycharm可以在terminal中运行,但是无法在run中运行(没有输出错误就停止了)

问题: pycharm的命令可以在terminal中运行,但是复制到无法在run中运行(没有输出错误就停止了) run中运行后什么错误提示都没有 搞不懂为什么 解决: 降低run中batch-size的大小,即可以运行 我并没有观察到…

Unity(2022.3.41LTS) - 后处理

目录 一、什么是后处理 二、后处理的工作原理 三、后处理的常见效果 四、如何在 Unity 中实现后处理 五、后处理的性能影响 六. 详细效果 一、什么是后处理 后处理是在场景渲染完成后,对最终图像进行的一系列操作。这些操作可以包括调整颜色、添加特效、模糊…

Windows Geth1.14.3私链搭建

geth下载官网:Downloads | go-ethereum 安装完成的目录 安装完后配置环境变量,在终端输入geth version 第一步:第一种创建账户方式geth account new --keystore keystore 创建一个账户,在当前目录下创建一个keystore的子目录&…

Linux工具使用

Linux编辑器-vim使用 1.vim的基本概念 在vim中,主要的三种模式分别是命令模式,插入模式和底行模式。 正常/普通/命令模式(Normal mode) 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,…

一本读懂数据库发展史的书

数据库及其存储技术,一直以来都是基础软件的主力。数据库系统的操作接口标准,也是应用型软件的重要接口,关系重大。 作为最“有感”的系统软件,数据库的历史悠久、品类繁多、创新活跃。 对数据库历史发展的介绍,有利…

CSS3视图过渡动画

概述 网站的主题切换无非就是文字、背景图片或者颜色,我们可以先来看下 Element UI 官网的切换主题的动效: PS:Antdesign UI的主题切换动画也是大同小异。 实现的两种方式 CSS 为主 <script setup> const changeTheme = (e) => {if (document.startViewTransi…

深度学习实用方法 - 选择超参数篇

序言 在深度学习的浩瀚领域中&#xff0c;超参数的选择无疑是通往卓越模型性能的一把关键钥匙。超参数&#xff0c;作为训练前设定的、用于控制学习过程而非通过学习自动获得的参数&#xff0c;如学习率、批量大小、网络层数及节点数等&#xff0c;直接影响着模型的收敛速度、…

MySQL索引(三)

MySQL索引(三) 文章目录 MySQL索引(三)为什么建索引&#xff1f;怎么建立索引为什么不是说索引越多越好什么时候不用索引更好 索引怎么优化索引失效如何解决索引失效 学习网站&#xff1a;https://xiaolincoding.com/ 为什么建索引&#xff1f; 1.索引大大减少了MySQL需要扫描…

线性约束最小方差准则(LCMV)波束形成算法及MATLAB深入仿真分析

阵列信号处理——线性约束最小方差准则(LCMV)波束形成算法及MATLAB深入仿真分析 目录 前言 一、LCMV算法 二、仿真参数设置 三、抗干扰权值计算仿真 四、不同干扰方位下抗干扰性能仿真 五、不同信噪比和干噪比下抗干扰性能仿真 总结 前言 在信号处理模块中&#xff0c;通…

day13JS-MoseEvent事件

1. MouseEvent的类别 mousedown &#xff1a;按下键mouseup &#xff1a;释放键click &#xff1a;左键单击dblclick &#xff1a;左键双击contextmenu &#xff1a;右键菜单mousemove &#xff1a;鼠标移动mouseover : 鼠标经过 。 可以做事件委托&#xff0c;子元素可以冒泡…

【网络】网络层协议——IP协议

目录 1.TCP和IP的关系 2.IP协议报文 2.1. 4位首部长度&#xff0c;16位总长度&#xff0c;8位协议 2.2. 8位生存时间 &#xff0c;32位源IP地址和32位目的IP地址 3.IP地址的划分 3.1.IP地址的表现形式 3.2.旧版IP地址的划分 3.2.1.旧版IP地址的划分思路 3.2.2.分类划…

鸿蒙开发 数组改变,ui渲染没有刷新

问题描述&#xff1a; 数组push, 数组长度改变&#xff0c;ui也没有刷新 打印出了数组 console.log(this.toDoData.map(item > ${item.name}).join(, ), this.toDoData.length) 原代码&#xff1a; Text().fontSize(36).margin({ right: 40 }).onClick(() > {TextPicker…

MySQL 数据库深度解析:安装、语法与高级查询实战

一、引言 在现代软件开发和数据管理领域中&#xff0c;MySQL 数据库凭借其高效性、稳定性、开源性以及广泛的适用性&#xff0c;成为了众多开发者和企业的首选。无论是小型项目还是大型企业级应用&#xff0c;MySQL 都能提供可靠的数据存储和管理解决方案。本文将深入探讨 MyS…

uni-app - - - - - 使用uview-plus详细步骤

uni-app - - - - - 使用uview-plus详细步骤 1. 使用HbuilderX创建空白项目2. 安装插件3. uview-plus配置使用3.1 main.js配置3.2 uni.scss配置3.3 App.vue配置3.4 pages.json 4. 重启Hbuilderx 1. 使用HbuilderX创建空白项目 2. 安装插件 工具 > 插件安装 > 前往插件市场…

Linux上安装Conda以管理Python环境

在Windows下装了Linux发行版Debian&#xff0c;以后不用来回开启VMware啦&#xff01;并在Debian中安装了Conda,记录一下所需命令(其他版本如Ubuntu中安装是一样的命令)。 目录 1.WSL 2.安装Conda 3.Python环境配置 1.WSL Install WSL | Microsoft Learn 微软官网 ①以管理…

STM32(F103ZET6)第二十四课:IAP离线固件升级

目录 开发需求IAP介绍内部的内存分区1.内部FLASH划分2.内部数据读取3.数据写入与擦除4.具体升级函数 IAP更新升级步骤1.系统启动流程2.IAP启动流程详解3.整体设计流程4.Boot Loader的代码编写5.APP1代码编写&#xff08;目前&#xff09;6.APP2代码编写&#xff08;待升级&…

WEB开发---使用HTML CSS开发网页实时显示当前日期和时间

自己刚开始学习html css知识&#xff0c;临时做个网页&#xff0c;实时显示当前日期和时间功能。 代码如下&#xff1a; test.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport&q…

python解释器[源代码层面]

1 PyDictObject 在c中STL中的map是基于 RB-tree平衡二元树实现&#xff0c;搜索的时间复杂度为O(log2n) Python中PyDictObject是基于散列表(散列函数)实现&#xff0c;搜索时间最优为O(1) 1.1 散列列表 问题&#xff1a;散列冲突&#xff1a;多个元素计算得到相同的哈希值 …

ARM 寻址方式(18)

立即寻址&#xff1a; 也叫作立即数寻址。 就是 立即数&#xff0c;本身就包含在了 指令当中。 举例&#xff1a; ADD R0, R0,#1 其中&#xff0c;#1 &#xff0c; 就是立即数&#xff0c;对于16进制的立即数&#xff0c; 需要在# 后加上 #0x. 寄存器寻址。 就是数据就在…