不知道你们有没有想过下面这件事?git
咱们平时调用
DELETE
在 MySQL 中删除的数据都去哪儿了?github
这还用问吗?固然是被删除了啊web
那么这里又有个新的问题了,若是在 InnoDB 下,多事务并发的状况下,若是事务A删除了 id=1
的数据,同时事务B又去读取 id=1
的数据,若是这条数据真的被删除了,那 MVCC 拿啥数据返回给用户呢?数据库
没错,这就须要了解一下 MySQL 的多版本并发的原理相关的东西,感兴趣的能够去看我以前写的这篇文章。微信
因此,实际状况中,调用了 DELETE
语句删除的数据并不会真正的被物理删除,这条数据其实还在那,只不过被打上了一个标记,标记已删除。并发
这其实跟咱们平常的操做——软删除,差很少是一个意思编辑器
在 MySQL 中, UPDATE
和 DELETE
操做本质上是同样的, 都属于更新操做,删除操做只不过是把某行数据中的一个特定的比特位标记为已删除,仅此而已。性能
那么问题又来了,那这些删除的数据若是一直这么堆下去,那不迟早把硬盘撑爆?学习
若是都玩儿成这样了,那 MySQL 还能像如今这样被大规模的用于生产环境中吗?那 MySQL 究竟是怎么玩的?flex
这就须要提到 Purge 操做了。
Purge操做是啥?
Purge 操做才是真正将数据(已被标记为已删除)物理删除的操做。
Purge 操做针对的数据对象,不只仅是某一行,还有其对应的索引数据和 Undo Log。
好的那么问题又来了。
问题是,Purge 操做何时会执行呢?实际上,你能够将执行 Purge 操做的线程(简称 Purge 线程)理解成一个后台周期性执行的线程。
Purge 线程能够有一个,也能够有多个,具体的线程数量能够由 MySQL 的配置项 innodb_purge_threads
来进行配置。固然,我相信你确定不记得在使用 MySQL 的时候配置过这个,由于 innodb_purge_threads
有个默认值,值为 4
。
InnoDB 会根据 MySQL 中表的数量和 Purge 线程的数量进行分配。
但正是由于有这种特性,Purge 线程的数量才须要根据业务的实际状况来作调整。举个例子,假设 DML 操做都集中在某张表,好比表1上...
你先等等,我打断一下......
什么叫 DML 操做?总喜欢搞些复杂的名词...DML(Data Manipulation Language)数据操做语句,实际上就是CRUD增删改查...
与之相似的概念还有DDL(Data Definition Language)数据定义语句,也就是CREATE
、DROP
和ALTER
等等.
以及DCL(Data Control Language)数据控制语句,也就是GRANT
、REVOKE
等等...
继续说回来,虽然 Purge 线程的数量是可配置的,可是也不是你想配多少就配多少的。否则你给它干个 10000
个线程,那不就直接原地 OOM 了吗?
innodb_purge_threads
的最大值为 32,并且并非咱们配了 32 InnoDB 就真的会启动 32 个 Purge 线程,为啥呢?举个很简单的例子,假设此时只有一张表,而后咱们配置了 32 个 Purge 线程。
你看着上面这个图问问本身,这「河里」吗?这样不只浪费了系统的资源,同时还使得不一样的 Purge 线程之间发生了数据竞争。不只如此,Purge 线程还可能跟用户线程产生竞争。
可是当系统中真的有 32 张表的时候,状况又不同了,一个 Purge 线程对应一张表,线程与线程之间就不会存在数据竞争,而且没有浪费系统资源,还可以提高执行 Purge 操做的性能。
这就是为啥 InnoDB 会根据实际状况来调整 MySQL 中 Purge 线程的数量,因此咱们在配置的时候也要按照实际状况来设置。
举个例子,若是你的数据库中,增删改 的操做只集中在某几张表上,则能够考虑将 innodb_purge_threads
设置的稍微低一点。相反,若是 增删改 的操做几乎每张表都有,那么 innodb_purge_threads
就能够设置的大一些。
了解完 Purge 线程自己以后,咱们就能够来了解 Purge 线程所针对的对象了。Purge 线程主要清理的对象是 Undo Logs,其次是行记录。
由于 Undo Log 能够分为:
因此更准确的说法是,Purge 线程清理的对象是 Update Undo Log 和 行记录,由于 Insert Undo Log 会在事务提交以后就会被删除。
咱们都知道 InnoDB 的 MVCC 的数据来源是一个一个 Undo Log 造成的单链表,而 Purge 线程就是用于按期清理 Undo Log 的,而且在清理完 删除数据所生成的 Undo Log 的时候,就会把对应的行记录给移除了。
那么问题又来了,Purge 线程每次会读取多少条件 Undo Log 记录呢?
很明显,它不是看当时的心情来决定取多少条的。它是经过配置项 innodb_purge_batch_size
来控制的,默认是 300。而后InnoDB会将这300条 Undo Log 分给innodb_purge_threads
个 Purge 线程。在清理的过程当中,Purge 线程还会释放 Undo Log 表空间内的文件。
本篇文章已放到个人 Github github.com/sh-blog 中,欢迎 Star。微信搜索关注【SH的全栈笔记】,回复【队列】获取MQ学习资料,包含基础概念解析和RocketMQ详细的源码解析,持续更新中。
若是你以为这篇文章对你有帮助,还麻烦点个赞,关个注,分个享,留个言。