TRUNCATE 语句到底因何而慢?

news2024/11/25 14:55:36

作者通过源码分析 truncate 语句形成慢 SQL 的原因和解决方案,并与 MySQL 5.7就相关实现逻辑进行对比。

问题现象

收到反馈某测试环境执行批量操作时,有 truncate 语句存在于慢查询日志中。担心上线后可能影响数据库,请求 DBA 配合分析。

关键配置

配置项说明
数据库版本MySQL 5.7
参数 long_query_time
慢查询阈值,单位为秒
0.1(100 毫秒)
参数 innodb_adaptive_hash_indexON

问题分析总结

总结下来主要有如何几个问题:

Q1: TRUNCATE 语句是如何执行的?fd 句柄不变化?为什么执行时间长?

TRUNCATE 语句如何执行?

关键堆栈:

关键操作 debug:

为什么执行时间长?

从以上堆栈可以看到,耗时过程主要是 row_drop_table_for_mysqlos_file_delete_func

其中:row_drop_table_for_mysql 主要是调用 btr_drop_ahi_for_table 执行 AHI 的 page 页的删除。os_file_delete_func 主要调用 unlink 执行文件的清理。

句柄为什么不变化?

假如需要 truncate 的表分配的 fd 为 43,truncate 过程中,会先将表 rename。这个时候这个 fd 会被关闭,43 就被释放了。然后执行 create table 操作。一般这个间隙过程很短,因此新建立的表可以使用被释放的 43 了,所以会看到 fd 没有变化。

如果 rename 之后,在内部执行 create table 之前,又打开了新文件,那这时候 fd 43 就会被其它打开的文件持有,truncate 之后表的 fd 也就会发生变化。

注意:MySQL 8.0 是真正使用 rename + create + drop实现的 truncate,但 MySQL 5.7 是通过文件的 truncate 实现的。

Q2: 如何分析 TRUNCATE 慢的问题?

方式一:慢日志?

只能看到慢的结果,无法确认原因。

方式二:执行计划?

不支持 truncate 语句。

方式三:profile

profile 结果来看,对于 truncate 语句,只能看到耗时过程都在System lock 上,无法看到更近一步的原因。

方式四:DEBUG

// 推荐设置
// 其中 T 其实是 MySQL 支持(在 trace 中打印时间)的,但官方文档中缺少了说明。已提交bug说明:Bug #111174

set global debug='d:t:T:i:n:N:o,/tmp/debug_3306.trace.f';
set global debug='';

  • ① 表示 show processlist 的线程 ID
  • ② 执行时间
  • ③ 函数调用层级
  • ④ 函数名称

MySQL 8.0 切换对比

// TRUNCATE
// 默认规范配置
// innodb_flush_method = on & innodb_flush_method = O_DIRECT
(root@127.1) [eolbimsdb] 08:44:46 15> truncate table t5;
Query OK, 0 rows affected (0.98 sec)

// 设置 innodb_adaptive_hash_index = off
(root@127.1) [eolbimsdb] 08:52:03 5> truncate table t5;
Query OK, 0 rows affected (0.03 sec)

// 设置 innodb_flush_method = fsync
(root@127.1) [eolbimsdb] 09:03:34 28> truncate table t5;
Query OK, 0 rows affected (1.04 sec)

// 设置  innodb_adaptive_hash_index = off & innodb_flush_method = fsync
(root@127.1) [eolbimsdb] 09:20:24 5> truncate table t5;
Query OK, 0 rows affected (0.22 sec)


// DROP
// 默认规范配置
// innodb_flush_method = on & innodb_flush_method = O_DIRECT
(root@127.1) [eolbimsdb] 10:05:41 9> drop table t5;
Query OK, 0 rows affected (0.94 sec)


// 设置 innodb_adaptive_hash_index = off & innodb_flush_method = O_DIRECT
(root@127.1) [eolbimsdb] 09:44:24 5> drop table t5;
Query OK, 0 rows affected (0.01 sec)

// 设置 innodb_flush_method = on & innodb_flush_method = fsync
(root@127.1) [eolbimsdb] 09:32:15 13> drop table t5;
Query OK, 0 rows affected (1.13 sec)

// 设置  innodb_adaptive_hash_index = off & innodb_flush_method = fsync
(root@127.1) [eolbimsdb] 09:25:10 14> drop table t5;
Query OK, 0 rows affected (0.19 sec)

Q3: 能否优化?慢在哪里?post_ddl 如何调用?

从 Q1 的结果中可以看出,执行的主要耗时在 row_drop_table_for_mysqlos_file_delete_func

MySQL 8.0 的优化措施

  1. row_drop_table_for_mysql 慢的问题,可以通过设置 innodb_adaptive_hash_index = off 进行优化;
  2. os_file_delete_func 慢的问题,可以设置 innodb_flush_method = O_DIRECT 或者配置表的 HARD LINK 进行优化。

MySQL 5.7 的优化措施

详见后面 3-Q1、3-Q4 部分。

post_ddl 如何调用?

MySQL 8.0 引入了 scope guard 功能:当定义了 scope guard 之后,会创建 Scope_guard 对象。正常情况下,当执行 return 操作前,会执行 scope guard 定义的逻辑。除非在函数结束前执行 Scope_guard 对象的 commit 操作。文件的删除功能实在 scope guard 的 cleanup_base 阶段调用是现的。

Q4: 生产执行 TRUNCATE 是否存在隐患?

从实现机制来看,主要有以下风险:

IO 压力

当触发 truncate 操作后,需要在短时间由数据库线程将文件 unlinktruncate,如果被处理的文件很大,服务器的 IO 压力可能会影响正常的数据库请求。

内存并发

在执行 truncatedrop 的过程中,由于需要对内存的数据进行清理,特别是对 LRU 和 flush_LRU 进行扫描,并释放对应的数据块。这个过程是需要逐个根据 buffer pool instance 获取 mutex 资源的。如果在业务高峰期,特别是 buffer pool 较大时,可能会影响正常的业务情况。

同时,执行 create drop table 操作时需要 dict_operation_lock 的 X 锁(RW_X_LATCH),而一些其他后台线程,比如 Main Thread 检查 dict cache 时,也需要获取 dict_operation_lock 的 X 锁,因此被阻塞。然后用户线程可能由于获取不到锁而处于挂起状态,当无法立刻获得锁时。更多参考:《Drop Table 对 MySQL 的性能影响分析》。

Q5: 不同版本对于 TRUNCATE 的实现是否存在差异?

通过对比 2-Q1 与 3-Q4:

MySQL 8.0 的 truncate 实现方式基本和 drop 实现方式相同,包括主要的耗时位置(都在 row_drop_table_for_mysqlos_file_delete_func)都是相同的。

MySQL 5.7 的 truncatedrop 实现差异较大,整个实现过程几乎是完全独立的代码。truncate 使用 row_truncate_table_for_mysqldrop 使用 row_drop_table_for_mysqltruncate 操作的主要的耗时有 dict_drop_index_treeos_file_truncate

DROP TABLE 优化失败分析

下面来看一个 MySQL 5.7 测试环境上线 DROP TABLE 优化方案失败问题。

  • 当 MySQL 5.7 使用规范配置启动时,从 debug-trace 过程来看,在row_drop_single_table_tablespacerow_drop_table_from_cache 函数执行期间根本没有耗时,所以实施优化方案后,没有效果;
  • 耗时的过程在 que_eval_sql: query: PROCEDURE DROP_TABLE_PROC ---> dict_drop_index_tree
  • row_drop_single_table_tablespace 的耗时被 MySQL 5.7 配置innodb_flush_method=O_DIRECT 优化了。

Q2:该优化是否适用于 MySQL 8.0?

设置 innodb_flush_method=O_DIRECT 的优化操作,同样适用于 MySQL 8.0。

Q3:MySQL 8.0 如何解决 DROP TABLE 时执行 DROP_TABLE_PROC 慢的问题?

  • WL#9536: InnoDB_New_DD: Support crash-safe DDL;
  • 依赖于自 Version 8.0.3 的 NEW DD;
  • 整个 drop 慢的 que_eval_sqlDROP_TABLE_PROC 被整体砍掉;
  • 包括 dict_drop_index_tree 在内的整个函数,都被砍了;
  • 具体实现机制,参考分析 NEW DD 实现方法。

Q4:MySQL 5.7 DROP TABLE 和 TRUNCATE 在实现机制、优化措施有何区别呢?

  • 执行 truncate 操作的耗时,仍然是在 dict_drop_index_treeos_file_truncate 这两个阶段;
  • os_file_truncate 的耗时:可以通过设置 innodb_flush_method=O_DIRECT 时间进行优化(不可以通过 hard link 进行优化);
  • dict_drop_index_tree 的耗时,暂时没有优化思路。了解更多:InnoDB 文件系统之文件物理结构。

Q5:5.7 慢查询为什么有时记录 TRUNCATE 执行慢,有时不记录?

根据源码,MySQL 是否记录慢查询判断时,主要有两个维度:一个是执行时间(不包括 utime_alter_lock);一个是执行扫描的行数,并对特殊的语句(如 call)进行了忽略。对于 truncate 操作而言,无论执行时间是多少,扫描行数都是 0。当配置了 min_examined_row_limit 大于 0 之后,一般 truncate 操作由于不满足该条件,都不会被记录到慢查询。

但是当 truncate 操作位于存储过程中时,在 truncate 操作之前有其它 DML 操作(如 insert selecct),这时候由于位于同一个 THD 下,在 MySQL 5.7 版本里面 thd->get_examined_row_count() 返回的结果其实是上一个 DML 语句的(这里应该是缺陷)。如果此时 truncate 操作的执行时间又超过了 long_query_time,那么此时这个 truncate 语句就会被记录慢查询。

同时,在 MySQL 8.0 针对 call 的语句,将不在单独记录记录的语句。而是记录为统一的 call 语句里面。需要看存储过程里面的语句执行情况,可以用 show profiles 查看。

慢查询记录堆栈

测试存储过程

DROP PROCEDURE truncate_test;
DELIMITER //
CREATE PROCEDURE truncate_test()
BEGIN
  insert into t1 select * from t1_bak;
  truncate table t1;
END
//
DELIMITER ;

call truncate_test();

mysql> call truncate_test();
Query OK, 0 rows affected (1 min 59.58 sec)
# Time: 2023-06-08T00:28:30.969993+08:00
# User@Host: root[root] @ localhost []  Id:     2
# Schema: db2  Last_errno: 0  Killed: 0
# Query_time: 119.177518  Lock_time: 0.000233  Rows_sent: 0  Rows_examined: 131072  Rows_affected: 131072
# Bytes_sent: 0
# Stored_routine: db2.truncate_test
use db2;
SET timestamp=1686155310;
insert into t1 select * from t1_bak;
# Time: 2023-06-08T00:28:31.375873+08:00
# User@Host: root[root] @ localhost []  Id:     2
# Schema: db2  Last_errno: 0  Killed: 0
# Query_time: 0.405734  Lock_time: 0.003310  Rows_sent: 0  Rows_examined: 131072  Rows_affected: 0
# Bytes_sent: 0
# Stored_routine: db2.truncate_test
SET timestamp=1686155311;
truncate table t1;

与 MySQL 8.0 对比

mysql> call truncate_test();
Query OK, 0 rows affected (2 min 28.51 sec)

# Time: 2023-06-07T17:18:39.215632Z
# User@Host: root[root] @ localhost []  Id:     8
# Query_time: 148.516478  Lock_time: 0.000372 Rows_sent: 0  Rows_examined: 172032
use testdb;
SET timestamp=1686158318;
call truncate_test();

MySQL 8.0 如何跟踪?

mysql> call truncate_test();
Query OK, 0 rows affected (2 min 24.84 sec)

mysql> 
mysql> 
mysql> show profiles;
+----------+--------------+-----------------------------------------+
| Query_ID | Duration     | Query                                   |
+----------+--------------+-----------------------------------------+
|        1 | 144.55113600 | insert into ltb2 select * from ltb3_bak |
|        2 |   0.29312375 | truncate table ltb2                     |
+----------+--------------+-----------------------------------------+
2 rows in set, 1 warning (0.00 sec)

以上包括 truncate 执行慢的分析,如针对细节有任何疑问和建议,欢迎留言交流。

关于 SQLE

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

SQLE 获取

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

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

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

相关文章

第八章 模型篇:transfer learning for computer vision

参考教程: transfer-learning transfer-learning tutorial 文章目录 transfer learning对卷积网络进行finetune把卷积网络作为特征提取器何时、如何进行fine tune 代码示例加载数据集构建模型fine-tune 模型模型作为feature extractor 定义train_loop和test_loop定…

【K8S系列】如何高效查看 k8s日志

序言 你只管努力,其他交给时间,时间会证明一切。 文章标记颜色说明: 黄色:重要标题红色:用来标记结论绿色:用来标记一级论点蓝色:用来标记二级论点 Kubernetes (k8s) 是一个容器编排平台&#x…

【C#每日一记】多线程实现的贪吃蛇原理—不允许你还不知道

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:uni…

软件测试技能,JMeter压力测试教程(一)

目录 前言 一、安装Java环境 二、安装JMeter环境 三、启动JMeter脚本测试 四、查看报告文件 前言 使用jmeter做压测的时候,在windows上不太稳定,所有一直在 Linux 服务器上使用 jmeter 做压力测试 本篇记录下 Linux上搭建 jmeter 环境&#xff0c…

分布式学习第二天 redis学习

目录 1. 数据库类型 1.1 基本概念 1.2 关系/非关系型数据库搭配使用 2. Redis 2.1 基本知识点 2.2 redis常用命令 2.4 redis数据持久化 3 hiredis的使用 4. 复习 1. 数据库类型 1.1 基本概念 关系型数据库 - sql 操作数据必须要使用sql语句 数据存储在磁盘 存储的…

如何使用CDN给OSS做加速详解

意义 用户直接访问OSS资源,速度会受到OSS下行带宽以及Bucket地域的限制,若通过CDNOSS的方式进行访问,带宽上限更高,并且可以将OSS的资源缓存至就近的CDN节点,通过CDN节点进行分发,可以缩短网络传输距离&am…

Linux学习之CentOS(八)--Linux系统的分区概念

不知不觉已经记录了8篇Linux学习随笔了,虽然还是漂浮在Linux系统的表面,还有很多很多没有学,但是坚持学下去、坚持写下去就是成功的!!!! 在讲Linux系统分区之前,首先得介绍一下硬盘…

【SpringCloud】2.微服务的熔断和降级

目 录 1. 熔 断1.1 发生场景1.2 熔断实现1.3 熔断测试 2. 降 级2.1 发生场景2.2 降级处理2.3 降级测试 在 上篇博客,我们完成了项目的基本搭建工作,那这篇博客就来实现一下微服务的熔断和降级。 1. 熔 断 1.1 发生场景 在前面,我们用 spri…

【Java高级语法】(八)反射机制:有朋友问反射到底是怎样玩的?看完这篇文章你就清楚了~

Java高级语法详解之反射机制 :one: 概念:two: 优势和缺点:three: 使用3.1 Class类3.2 获取类的结构信息- 构造函数3.3 获取类的结构信息- 方法3.4 获取类的结构信息- 字段3.5 动态创建对象、调用方法和设置属性3.6 动态代理 :four: 底层原理:five: 应用场景:ear_of_rice: 总结:…

SedonaSQL 聚合函数使用说明

ST_Envelope_Aggr 函数说明: 返回几何的外边界 语法: ST_Envelope_Aggr (A:geometryColumn) 支持版本: v1.0.0 Spark SQL 举例说明: SELECT ST_Envelope_Aggr(pointdf.arealandmark) FROM pointdf运行示例(AggregateFunctionTest.java): ST_Intersection_Aggr 函数说明: …

大文件如何传输到电脑?亲测又快又简单!

我们平时可以因为各种原因,如更换新电脑、高清视频分享等,需要将大文件传输到另一台电脑上。大文件如何传输到电脑?相信这是很多朋友都想知道如何实现吧。我们为您提供了2种轻松将大文件从PC传输到PC的方法。话不多说,上技巧! 方…

腾讯云服务器地域有什么区别?怎么选比较好

腾讯云服务器地域有什么区别?云服务器地域怎么选择?地域是指云服务器所在机房的地理位置,用户距离地域越近网络延迟越低,速度越快,所以地域就近选择即可。广州上海北京等地域网站域名需要备案,中国香港或其…

SpringBoot使用MockMVC单元测试Controller

前言: 在SpringBoot应用程序中,Controller是接受客户端请求并返回响应数据的核心组件。为了保证Controller的正确性和稳定性,我们可以使用MockMVC框架进行单元测试。MockMVC是Spring框架提供的一个HTTP客户端,用于模拟HTTP请求和响…

2023年智能优化算法之——增长优化器Growth Optimizer(GO),附MATLAB代码

增长优化器的主要设计灵感来源于个人在社会成长过程中的学习和反思机制。学习是个体通过从外部世界获得知识而成长的过程。反思是检查个人自身不足并调整个人学习策略以帮助个人成长的过程。参考文献如下: Zhang, Qingke, et al. “Growth Optimizer: A Powerful M…

二维码在固定资产实物盘点中的应用

很多企业为了掌握固定资产的后续使用情况和状态,会定期对投入使用的固定资产进行盘点,然而固定资产常会出现分散情况,在这种情况下让财务人员到达每个固定资产的所在处进行实地盘点显得极为不现实。 也有不少企业会在盘点过程中使用到固定资…

聊天室(一)___常见的基本功能实现

最近搞聊天室的人还挺多,正好自己也弄就总结自己遇到必不可少的一些功能,本篇文章主要为自己和看到我文章的人一种思路,希望大家不要把聊天室想的太复杂。 上图是我自己做的一个聊天室,类似微信的单聊群聊收藏等功能,根…

python+requests接口自动化框架详解,没有比这个更详细的了

目录 为什么要做接口自动化框架 正常接口测试的流程是什么? 一、接口框架如下: 二、接口的数据规范设计---Case设计 2.1注册接口用例 2.2登录接口用例 三、创建utils包:用来存放公共的类 3.1 ParseExcel.py 操作封装excel的类&#xf…

【AI工具】-Stable Diffusion本地化部署教程

前言 今天我们要介绍的是时下最流行的AI绘图软件Stable Diffusion,虽然Diffusion.ai已经开放api,但是长时间的商业化调用我们需要购买很多的金币。所以我们需要找一个平替的AI绘图平台,现在主流市场中AI绘图软件主要就是OpenAI的DALLE、midj…

SSM会议管理系统

SSM会议管理系统 后端基于SSM、前端基于Freemarker写的会议管理系统、使用JDK8、mysql使用5.7版本 技术栈 Spring SpringMVC MyBatis Mysql Freemarker jqueryajax[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGo0luHu-1687163482019)(img.png)] …

【Python 随练】打印水仙花数

题目: 打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数 简介: 在本篇博客中,我们将解决一个经典的数学问题:打印出所有的水仙花数。水仙花数是指一…