前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何快速删除InnoDB中的大表?

如何快速删除InnoDB中的大表?

作者头像
腾讯数据库技术
发布于 2018-06-05 09:09:45
发布于 2018-06-05 09:09:45
8.9K30
代码可运行
举报
运行总次数:0
代码可运行

1. 背景

在使用MySQL时,如果有大表的存储引擎是InnoDB,并且系统参数innodb_file_per_table设置为1,即每个文件对应一个独立的表空间,当对这些大表进行DROP TABLE时,有时会发现整个数据库系统的性能会有显著下降,包括一些只涉及几行数据的简单SELECT查询和DML语句,而且这些语句和正在删除的大表没有关系。造成这种现象的原因是什么呢?通过什么方式能缓解和避免这个问题呢?

2. 已知的瓶颈

Percona曾经在MySQL官方5.5.23之前的版本中遇到过这个问题,并且提供了一种叫Percona Lazy Drop的补丁。简单来说,他们认为这个问题的瓶颈在CPU。在删除一个有独立表空间的大表时,需要对buffer pool中所有和这个表空间有关的数据页做清理工作,包括从AHI,flush list和LRU list上移除,而在这个清理过程中,会一直持有buffer pool的mutex。如果buffer pool配置特别大,比如500 GB大小,持有这个mutex的事件会较长,导致其他连接被阻塞住,从而导致系统性能的下降。Percona Lazy Drop就是在清理buffer pool这里做了优化,尽量短时间和小粒度的持有mutex。

MySQL官方在5.5.23版本中也实现了一个lazy drop的功能,但和Percona的实现方式不一样:在移除flush list时,会有一个条件判断,如果已经处理了超过一定数量的page,会强制释放当前持有的buffer pool mutex和flush list mutex,并且让出CPU,过一会儿再重新拿回锁继续清理flush list;对于LRU list,则不做处理,因为当这个表被删除后,这些数据页最终会在LRU算法调度下被回收。相关的函数调用图为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
buf_LRU_flush_or_remove_pages(BUF_REMOVE_FLUSH_NO_WRITE) --> buf_LRU_remove_pages --> buf_flush_dirty_pages --> buf_pool_mutex_enter
                                                                                                            |__ buf_flush_or_remove_pages --> buf_flush_list_mutex_enter
                                                                                                            |                             |__ buf_flush_try_yield
                                                                                                            |                             |__ buf_flush_list_mutex_exit
                                                                                                            |__ buf_pool_mutex_exit

Percona在后续版本中移植了MySQL官方5.5.23中的lazy drop,并且移除了自己之前实现的Percona Lazy Drop方案。

3. IO问题

尽管已经有了上述的buffer pool层面的优化,我们在使用MySQL 5.6或者5.7时依然发现删除大表对系统性能还是会产生显著的影响,说明DROP TABLE还有其他的性能瓶颈,尤其是对于这样一种业务场景:并发地删除多个大表。在这种场景下,数据库实例几乎处于不可服务的状态。通过抓取这种状态下的mysqld进程的堆栈,我们发现此时性能瓶颈不在上面介绍的buffer pool mutex上,而是在删除ibd文件的IO上。IO的瓶颈是怎样具体地导致系统性能下降的呢?通过阅读MySQL 5.7的源码可以看到,整个DROP TABLE过程可以简单地概括为:

  • 获取dict_sys->mutex这个数据字典锁
  • 启动一个innodb事务
  • 更新数据字典,包括内存中的数据和mysql库下的数据字典表
  • lazy drop逻辑,清理buffer pool的flush list,会多次持有和释放buffer pool mutex以及flush list mutex
  • 写入MLOG_FILE_DELETE类型的redo日志
  • unlink ibd文件
  • 提交innodb事务
  • 释放dict_sys->mutex

这个过程表明,删除ibd文件时是持有dict_sys->mutex的,如果文件大小很大,比如50GB以上,unlink操作会比较耗时,dict_sys->mutex会较长时间被当前连接持有,此时,并发的其他DROP TABLE会阻塞在dict_sys->mutex上,更糟糕的是,并发的被阻塞的DROP TABLE会持有所有的table cache lock,因为它是在清理table cache中和该表相关的数据时被dict_sys->mutex阻塞的,于是,会导致接下来的几乎所有语句都阻塞在table cache lock上,从show processlist结果上看,就表现为SELECT和DML语句状态是”Opening tables”,而DROP TABLE语句状态为”Checking permissions”。被阻塞的DROP TABLE语句(持有所有table cache lock)的相关函数调用为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql_execute_command --> mysql_rm_table --> tdc_remove_table --> table_cache_manager.lock_all_and_tdc
                                                              |__ Table_cache_manager::free_table --> intern_close_table --> closefrm --> ha_innobase::close --> row_prebuilt_free --> dict_table_close --> mutex_enter(&dict_sys->mutex)
                                                              |__ table_cache_manager.unlock_all_and_tdc

DROP TABLE的源代码调用关系大致为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
row_drop_table_for_mysql --> row_mysql_lock_data_dictionary
                         |__ trx_start_for_ddl
                         |__ clean up data dictionary
                         |__ row_drop_table_from_cache
                         |__ row_drop_single_table_tablespace --> fil_delete_tablespace --> buf_LRU_flush_or_remove_pages
                         |                                                              |__ os_file_delete --> unlink
                         |__ row_mysql_unlock_data_dictionary

4. 解决方案

从上面介绍可以看到,DROP TABLE可能存在两个性能瓶颈,一个是buffer pool的清理,另一个是ibd文件的删除,怎么缓解或者解决这个问题呢?

4.1 不改动源码情况
  • 尽可能在低峰期进行删除表的操作;
  • 对于buffer pool问题,适当增大innodb_buffer_pool_instances参数,尽量减小持有buffer pool mutex对其他语句的影响;
  • 对于IO问题,删除表之前对ibd文件手动创建一个硬链接,让DROP TABLE可以快速执行结束,等到低峰期再真正从磁盘上删除文件;
4.2 改动源码方案
  • 考虑在unlink文件前释放dict_sys->mutex dict_sys->mutex是用来保护内存中的数据字典,以及mysql库下的数据字典表,从源码可以看到,在unlink ibd文件之前,所有的数据字典操作已经结束,其实是可以释放掉dict_sys->mutex的。 这个方案可以快速简单地解决dict_sys->mutex是性能瓶颈的问题,但是,这个方案是不安全的,因为提前释放dict_sys->mutex意味着需要提前提交innodb事务,于是上述的DROP TABLE过程变为: 那么就会存在这样一个情况:如果系统crash发生在释放dict_sys->mutex后和unlink文件前,那么当数据库重新启动后,从InnoDB数据字典的角度看,DROP TABLE事务已经成功提交了,数据字典里已经没有这个表了,但是磁盘上还存在ibd文件;这个问题一方面会导致磁盘空间的浪费,另外一方面会导致CREATE TABLE失败,如果表名和之前删除的表名一样。可能有人会问,不是在提交事务前写入了一条MLOG_FILE_DELETE类型的redo日志吗,那么数据库启动后重做redo日志时难道不会删除磁盘上遗留的ibd文件?遗憾的是,现在crash recovery的逻辑中,对于MLOG_FILE_DELETE类型的日志,只把它当作是一条“告知”含义的日志记录,不会去删除本应被删除的文件(在UNIV_HOTBACKUP代码分支的crash recovery逻辑中会,但这个分支不在正常的server编译路径中)。 如果想要用这个方案,就需要修改MLOG_FILE_DELETE日志的语义,也就是说在crash recovery中,当执行这条日志时,如果磁盘上该文件还存在,则将该文件删除,同时,将DROP TABLE过程调整为:
    • 获取dict_sys->mutex这个数据字典锁
    • 启动一个innodb事务
    • 更新数据字典,包括内存中的数据和mysql库下的数据字典表
    • lazy drop逻辑,清理buffer pool的flush list,会多次持有和释放buffer pool mutex以及flush list mutex
    • 启动一个mini-transaction
    • 写入MLOG_FILE_DELETE类型的redo日志
    • 提交innodb事务
    • 释放dict_sys->mutex
    • 提交mini-transaction
    • unlink ibd文件
    • 获取dict_sys->mutex这个数据字典锁
    • 启动一个innodb事务
    • 更新数据字典,包括内存中的数据和mysql库下的数据字典表
    • lazy drop逻辑,清理buffer pool的flush list,会多次持有和释放buffer pool mutex以及flush list mutex
    • 写入MLOG_FILE_DELETE类型的redo日志
    • 提交innodb事务
    • 释放dict_sys->mutex
    • unlink ibd文件
  • 假设已经没有dict_sys->mutex瓶颈,单纯地unlink一个大文件也会影响系统其他的IO操作,因为需要涉及大量的文件系统日志操作(详见之前推送的文章”Linux删除文件过程解析”),所以另一个可以考虑的方案是将一个大文件的删除分成多次的truncate操作。具体来说,在DROP TABLE中,将之前的unlink调用替换为rename,将ibd文件加上一个后缀,比如.trash,然后将这个重命名后的文件加入到一个队列中,DROP TABLE就继续后面的提交事务释放锁。真正的文件删除可以在innodb master thread中进行,或者重新启动一条专门的线程负责在后台从队列中拿文件并小批量truncate。 这个方案需要注意的一个问题是重命名的文件名不能重复,因为有dict_syc->mutex的保护,用一个简单的计数器就可以实现,但考虑到重启的情况,用时间戳会更好一些;另一个问题是,如果重命名的文件依然在之前的数据库目录下,那么在后台线程真正删除掉文件之前,DROP DATABASE会失败,一种方案是DBA可以手动删除掉trash文件,另一个方案是让用户指定一个其他的临时目录来存放rename后的文件,注意临时文件目录需要和数据目录在同一个挂载点下。

5. 总结

本文介绍了MySQL DROP TABLE可能存在的性能瓶颈,导致瓶颈的具体原因,以及相关的解决方案和思路。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-12-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯数据库技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
3 条评论
热度
最新
沙发沙发
沙发沙发
回复回复点赞举报
谢谢分享
谢谢分享
回复回复点赞举报
太赞了,正在找这方面的解决方法,总算找到了,十分感谢
太赞了,正在找这方面的解决方法,总算找到了,十分感谢
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
技术分享 | 如何优雅的删除 Zabbix 的 history 相关历史大表
前段时间,客户反馈 Zabbix 实例的 history_str 表数据量很大,导致磁盘空间使用率较高,想要清理该表,咨询是否有好的建议。想着正好最近学习了相关的知识点,正好可以检验一下学习成果,经过实践的检验,最终考试合格,客户也比较满意,于是便有了此文。
爱可生开源社区
2023/04/18
1.2K0
快速安全删除MySQL大表
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
用户1148526
2019/10/22
5.8K1
MySQL:innodb_open_files参数及其周边
这个参数控制的是实际的Iinnodb层同时打开的文件数量(open),当然大于了也不会报错,通过LRU链表淘汰即可。这个一点和open_files_limit是不一样的。
老叶茶馆
2021/07/09
1.8K0
MySQL:innodb_open_files参数及其周边
How does InnoDB behave without a Primary Key(11.InnoDB在没用主键情况下的行为)
今天下午,我和Arjen Lentz讨论了InnoDB在没有声明主键的情况下的行为,这个话题很有趣,也没有足够的文档证明,所以有必要写一个简短的帖子。
冬天里的懒猫
2020/09/01
6490
如何让xtrabackup恢复速度提升20倍?
简介   Xtrabackup是由percona开源的免费数据库热备份软件,它能对InnoDB数据库和XtraDB存储引擎数据库进行非阻塞的备份,其具备以下一些优点:   1)备份速度快,物理备份可靠
腾讯数据库技术
2018/06/05
1.5K0
技术分享 | 大量 Opening tables 案例分析
本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
爱可生开源社区
2020/12/30
1.6K0
Innodb Buffer Pool详解
导读 数据库为了高效读取和存储物理数据,通常都会采用缓存的方式来弥补磁盘IO与CPU运算速度差。InnoDB 作为一个具有高可靠性和高性能的通用存储引擎也不例外,Buffer Pool就是其用来在内存中缓存数据页面的结构。本文将基于MySQL-8.0.22源码,从buffer pool结构、buffer pool初始化、buffer pool管理、页面读取过程、页面淘汰过程、buffer pool加速等方面介绍buffer pool的实现原理。 第一部分、Buffer pool结构 Buffer pool不
腾讯数据库技术
2023/01/30
1.4K0
Innodb Buffer Pool详解
mysql体系结构
2用户名密码验证(通过授权表做的验证数据库一启动,会把授权表加载到内存中 mysql.user mysql.db mysql.table_priv mysql.column_priv)
萧晚歌
2021/11/17
1.1K0
MySQL AHI 实现解析
该文章讲述了在MySQL中,如何通过Aging/Adaptive Hash Index (AHI)机制进行数据分页查询。主要介绍了AHI的原理、数据结构、操作步骤和性能影响。同时,也介绍了如何通过MySQL的innodba_monitor工具对AHI的性能进行监控。
musazhang
2016/12/22
5.8K0
MySQL  AHI 实现解析
Buffer pool 详解
提示:公众号展示代码会自动折行,建议横屏阅读 ---- 1 综述 buffer pool 是 innodb的数据缓存,保存了 data page、index page、undo page、insert buffer page、adaptive hash index、data dictionary、lock info。buffer pool绝大多数page都是 data page(包括index page)。innodb 还有日志缓存 log buffer,保存redo log。 下图可以看出来 inno
腾讯数据库技术
2019/12/03
2.7K0
Buffer pool 详解
利用硬链接和truncate降低drop table对线上环境的影响
作者简介 肖鹏 微博研发中心数据库技术负责人,主要负责微博数据库(MySQL/Reids/HBase/Memcached)相关的业务保障,性能优化,架构设计以及周边的自动化系统建设。10年互联网数据库
数据和云
2018/03/06
1.6K0
利用硬链接和truncate降低drop table对线上环境的影响
MySQL-8.0 | 数据字典最强解读
数据字典(Data Dictionary)中存储了诸多数据库的元数据信息如图1所示,包括基本Database, table, index, column, function, trigger, procedure,privilege等;以及与存储引擎相关的元数据,如InnoDB的tablespace, table_id, index_id等。MySQL-8.0在数据字典上进行了诸多优化,本文将对其进行逐一介绍。
数据和云
2019/05/13
4K0
MySQL详解复杂原理
MySQL InnoDB 引擎现在广为使用,它提供了事务,行锁,日志等一系列特性,本文分析下 InnoDB 的内部实现机制,MySQL 版本为 5.7.24,操作系统为 Debian 9。
用户4283147
2022/10/27
3620
MySQL详解复杂原理
为什么别人能用好 MySQL?万字详解其复杂原理
MySQL InnoDB 引擎现在广为使用,它提供了事务,行锁,日志等一系列特性,本文分析下 InnoDB 的内部实现机制,MySQL 版本为 5.7.24,操作系统为 Debian 9。
乔戈里
2020/04/23
7490
为什么别人能用好 MySQL?万字详解其复杂原理
TDSQL-C Serverless 如何“弹”得更稳?
云原生数据库 TDSQL-C 使用计算存储分离的架构,计算资源和存储资源解耦,可以提供PB级的存储容量供用户按需使用。而 Serverless 架构是将计算资源做到极致弹性,和购买的实例规格解耦,根据用户数据库实际的负载,自动启停和自动扩缩容,按使用计费。其中计算资源主要是 CCU(CPU+内存),CPU 可以由 cgroup 或者 docker 等技术限制,内存分配给数据库进程,大部分由 Buffer Pool 模块使用,目的是缓存用户数据,Buffer Pool 内存的分配与释放过程涉及用户数据的分布,搬迁,还有内核中全局资源的互斥等等。本文将详细介绍 TDSQL-C Serverless 在内核做的一系列优化,让数据库弹得更稳。
腾讯云数据库 TencentDB
2023/08/10
3340
TDSQL-C Serverless 如何“弹”得更稳?
MLOG_CHECKPOINT缺失下紧急数据恢复
生产环境MySQL数据库,架构是一主一从,可以双机切换,MySQL版本是5.7.24-enterprise-commercial-advanced-log。当时是存储MySQL的机房突然断电。主从机器重启后,MySQL都无法启动。两台机器都是同样错误,错误日志显示:
数据和云
2021/08/27
1.5K0
优雅的drop掉mysql库中1TB大表
要是问大家,知道怎么从mysql数据库中drop掉业务表,很多人肯定会说,so easy,用drop table t_test语句不就完事了,这是初生牛犊不怕虎,你要是如此简单,去线上业务库中drop掉一张1TB大小的表,造成长时间的业务无法访问数据库,更严重,导致数据库崩溃,宕机都是可能的。
IT大咖说
2020/09/04
2.5K0
优雅的drop掉mysql库中1TB大表
MySQL - 存储引擎初探
存储引擎是 MySQL 中具体与文件打交道的子系统,它是根据 MySQL AB 公司提供的文件访问层抽象接口定制的一种文件访问机制,这种机制就叫作存储引擎 。
小小工匠
2021/08/17
7930
记一次出乎意料的semaphore超时导致crash分析过程(转)
DBA应该对InnoDB: Semaphore wait has lasted > 600 seconds. We intentionally crash the server because it appears to be hung. 一点都不陌生,MySQL后台线程srv_error_monitor_thread发现存在阻塞超过600s的latch锁时,如果连续10次检测该锁仍没有释放,就会触发panic避免服务持续hang下去。
田帅萌
2019/06/15
2.2K0
故障分析 | mysql 5.6 升级到 8.0 失败一例处理
现居珠海,主要负责 Oracle、MySQL、mongoDB 和 Redis 维护工作。
用户1278550
2021/10/18
1.5K0
相关推荐
技术分享 | 如何优雅的删除 Zabbix 的 history 相关历史大表
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验