- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
本文分享自华为云社区《为什么表数据删掉一半,表文件大小不变?》,作者: JavaEdge。
由于DB占用空间太大,我删除了大表的一半数据,可为啥这表文件的大小没变?
数据库表的空间回收到底是怎么做的呢?
InnoDB表包含:
MySQL版本:
为何直接删除表数据无法回收表空间?
如何正确回收空间?
表数据
该行为由参数innodb_file_per_table决定:
从MySQL 5.6.6版本开始,默认值为ON。
推荐无论哪个版本,都将该值设为ON:
因此后续讨论都默认该设置为ON。
删除整个表时,可用drop table回收表空间。但更常见的场景是删除某些行,于是就会发现:表中的数据被删除了,但表空间没有被回收!
InnoDB索引示意图
假设,我们要删掉D4,InnoDB引擎只会把D4这个记录标记为删除。若之后要再插入一个ID在300、600之间的记录时,可能会复用该位置。但磁盘文件并不会缩小。
整个数据页就能被复用了。
但是,数据页的复用跟记录的复用不同:
若将数据页pageA上的所有记录删除后,pageA会被标记为可复用。这时若插入一条ID=20的记录,需要使用新页时,pageA就能被复用。
若相邻两个数据页利用率都很小,系统就会把这俩页上的数据合到其中一个页上,另外一个数据页就被标记为【可复用】。
所有的数据页都会被标记为【可复用】,但磁盘上的文件不会变小。
delete命令其只是将记录的位置或数据页标记为“可复用”,但磁盘文件的大小不会变。即通过delete命令不能回收表空间。这些可以复用但实际没有被使用的空间,看起来就像“空洞”。
不仅删除数据会造成空洞,插入数据也会。
若数据按索引递增顺序插入,则索引是紧凑的。但若数据是随机插入的,就可能造成索引的数据页分裂。
假设pageA已满,此时再插入一行数据,会怎样呢?
插入数据导致页分裂
由于pageA满,再插入ID=550时,就得再申请一个新页面pageB保存数据。页分裂完成后,pageA末尾就留下空洞(实际可能不止1个记录的位置是空洞)。
更新可理解为删除一个旧值,再插入新值。所以也会造成空洞。
综上,经过大量增删改的表,都可能存在空洞。若能去掉这些空洞,就能达到收缩表空间的目的。重建表,就能达到目的。
若现在有一表A,要做空间收缩,为了去掉表中存在的空洞,可新建一个与表A结构相同的表B,然后按主键ID递增顺序,把数据一行行从表A里读出,再插入表B。
因为表B是新建表,所以表A主键索引上的空洞,在表B都不存在。显然表B的主键索引更紧凑,数据页的利用率更高。若将表B作为临时表,数据从表A导入表B的操作完成后,用表B替换A,就达到收缩表A空间的效果。
可用
alter table A engine=InnoDB
重建表。在MySQL 5.5前,这命令的执行流程跟我们前面描述的差不多,区别只是这个临时表B不需要自己创建,MySQL会自动完成转存数据、交换表名、删除旧表的操作。
改锁表DDL:
往临时表插入数据的过程最耗时,若在此过程中,有新数据要写入到表A,就会造成数据丢失。因此,整个DDL过程中,表A不能有更新,即这DDL不是Online的。
MySQL 5.6版本引入Online DDL,优化了该操作流程。
用临时文件替换表A的数据文件。
Online DDL:
和上图不同在于,由于日志文件记录和重放操作的存在,该方案在重建表的过程中,允许对表A做增删改,这就是Online DDL名字来源。
DDL之前还要拿MDL写锁的,这也能叫Online DDL?
确实,图Online DDL流程中,alter语句在启动的时候需获取MDL写锁,但该写锁在真正拷贝数据前就退化成读锁了。
为了实现Online,MDL读锁不会阻塞增删改操作。
为了保护自己,禁止其他线程对该表同时做DDL。对一个大表,Online DDL最耗时过程就是拷贝数据到临时表时,这个步骤的执行期间可接受增删改操作。所以,相对于整个DDL过程,锁的时间非常短。对业务来说,就可认为是Online的。
上述这些重建方法都会扫描原表数据、构建临时文件。对于大表,这很消耗IO和CPU。因此,若是线上服务,要谨慎控制操作时间。若想要较安全的操作,推荐使用GitHub开源的gh-ost。
图改锁表DDL中,把表A中的数据导出来的存放位置叫作tmp_table。这是个临时表,创建在server层。
在图4中,根据表A重建出来的数据是放在“tmp_file”,该临时文件是InnoDB在内部创建的。整个DDL过程都在InnoDB内部完成。对于server层,没有把数据挪动到临时表,是个“原地”操作,这就是“inplace”名称来源。
若有一个1TB的表,磁盘空间1.2TB,能做个inplace的DDL吗?
不能。因为,tmp_file也是要占用临时空间的。重建表的这个语句alter table t engine=InnoDB,其隐含意思:
alter table t engine=innodb,ALGORITHM=inplace;
跟inplace对应的就是拷贝表的方式了,用法是:
alter table t engine=innodb,ALGORITHM=copy;
当你使用ALGORITHM=copy的时候,表示的是强制拷贝表,对应的流程就是图3的操作过程。
inplace跟Online是不是就一个意思?
不是的,只是在重建表这个逻辑中刚好是这样。
若给InnoDB表的一个字段加全文索引:
alter table t add FULLTEXT(field_name);
这个过程是inplace的,但会阻塞增删改操作,非Online。
如果说这两个逻辑之间的关系是什么的话,可以概括为:
使用optimize table、analyze table和alter table这三种方式重建表
从MySQL 5.6版本开始
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!