一:概念

  - 这里,我们还是针对 MySQL 中应用最广泛的 InnoDB 引擎展开讨论。

  - 一个 InnoDB 表包含两部分,即:表结构定义和数据。

    - 在 MySQL 8.0 版本以前,表结构是存在以.frm 为后缀的文件里。

    - 而 MySQL 8.0 版本,则已经允许把表结构定义放在系统数据表中了。

    - 因为表结构定义占用的空间很小,所以我们今天主要讨论的是表数据。

二:表数据既可以存在共享表空间里,也可以是单独的文件。由参数 innodb_file_per_table 控制。

  - 概念

    - 这个参数设置为 OFF 表示的是,表的数据放在系统共享表空间,也就是跟数据字典放在一起。

    - 这个参数设置为 ON 表示的是,每个 InnoDB 表数据存储在一个以 .ibd 为后缀的文件中。

  - 从 MySQL 5.6.6 版本开始,它的默认值就是 ON 了。

    - 因为,一个表单独存储为一个文件更容易管理,而且在你不需要这个表的时候,通过 drop table 命令,系统就会直接删除这个文件。

    - 而如果是放在共享表空间中,即使表删掉了,空间也是不会回收的。 

三:数据删除流程

  - 数据

    - 

  - 删除

    - 假设,我们要删掉 300 的记录,InnoDB 引擎只会把 300 这个记录标记为删除。

    - 但是, 如果之后要再插入一个 在 300-500 之间的记录时,可能会复用这个位置。(磁盘文件的大小并不会缩小)。

    - 如果我们删掉了一个数据页上的所有记录,整个数据页就可以被复用了。(如果相邻的两个数据页利用率都很小,会整合两个数据页,一个数据页就被标记为可复用。)

  - 如果我们用 delete 命令把整个表的数据删除呢?

    - 结果就是,所有的数据页都会被标记为可复用。但是磁盘上,文件不会变小。

  - 结论

    - Delete 命令其实只是把记录的位置,或者数据页标记为了“可复用”,但磁盘文件的大小是不会变的。

    - 也就是说,通过 Delete 命令是不能回收表空间的。

    - 这些可以复用,而没有被使用的空间,看起来就像是“空洞”。

    - 实际上,不止是删除数据会造成空洞,插入数据也会。

      - 如果数据是按照索引递增顺序插入的,那么索引是紧凑的。但如果数据是随机插入的,就可能造成索引的数据页分裂。

      - 假设我要写入的 page A 已经满了,在插入一行数据,也会导致页分裂。

      - 另外,更新索引上的值,可以理解为删除一个旧的值,再插入一个新值。不难理解,这也是会造成空洞的。

    - 也就是说,经过大量增删改的表,都是可能是存在空洞的。

    - 所以,如果能够把这些空洞去掉,就能达到收缩表空间的目的。

四:重建表(去除空洞)

  - 如果需要重建表,那么你能想出他是如何构建表的?

    - 建立 临时表B,把 A 表数据根据递增的关系,放入 B 中,最后用 B 替换 A。完成重构。(A 的空间收缩,空洞消失)

  - 而在MySQL 5.6 版本开始引入的 Online DDL,对这个重建操作流程做了优化。

    - 流程

      - 建立一个临时文件,扫描表 A 主键的所有数据页。

      - 用数据页中表 A 的记录生成 B+ 树,存储到临时文件中。

      - 生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中。

      - 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件。

      - 用临时文件替换表 A 的数据文件。

    - 区别

      - 不同之处在于,由于日志文件记录和重放操作这个功能的存在,这个方案在重建表的过程中,允许对表 A 做增删改操作。

      - 这也就是 Online DDL 名字的来源。

五:如何重建表?

  - alter table t engine = InnoDB(也就是 recreate)

    - OnLine DDL

  - analyze table t

    - 其实不是重建表,只是对表的索引信息做重新统计,没有修改数据,这个过程中加了 MDL 读锁;

  - optimize table t

    - 等于 recreate+analyze。

《Mysql - 为什么表数据删掉一半,表文件大小不变?》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. 页面嵌套iframe时,怎样让iframe高度根据自身内容高度自适应

    总体思路是这样的,因为iframe里页面的内容是动态加载的,而且电脑屏幕宽度发生变化时,也得相应的去改变iframe标签的高度(如果高度确定就不用这么麻烦了): 首先,我们在父页面中定义一个方法,用来 ...

  2. 1829:【02NOIP提高组】自由落体

    #include<bits/stdc++.h> using namespace std; double h,s1,v,k,l; int n,ans; int main() { cin> ...

  3. 前端逼死强迫症系列之javascript续集

    一.javascript函数 1.普通函数 function func(){ } 2.匿名函数 setInterval(function(){ console.log(123); },5000) 3. ...

  4. vue日常学习

    1.$refs可以用来进行父子级间通信.ref被用于作为子组件的索引ID,用以方便的在js中直接访问子组件.用法如下parent.$refs.idname 使用方法: 在父级元素上加上ref属性 &l ...

  5. Java核心复习——J.U.C AbstractQueuedSynchronizer

    第一眼看到AbstractQueuedSynchronizer,通常都会有这几个问题. AbstractQueuedSynchronizer为什么要搞这么一个类? 这个类是干什么的.有什么用? 这个类 ...

  6. python wmi远程数据获取

  7. OpenJudge计算概论-分数求和

    /*====================================================== 1006:分数求和 总时间限制: 1000ms 内存限制: 65536kB 描述 输入 ...

  8. angular之Rxjs异步数据流编程入门

    Rxjs介绍 参考手册:https://www.npmjs.com/package/rxjs 中文手册:https://cn.rx.js.org/ RxJS 是 ReactiveX 编程理念的 Jav ...

  9. angular中父组件给子组件传值-@input

    1. 父组件调用子组件的时候传入数据 <app-header [msg]="msg"></app-header> 2. 子组件引入 Input 模块 imp ...

  10. PorterDuffXfermode之PorterDuff.Mode.MULTIPLY

    package com.loaderman.customviewdemo.view; import android.content.Context; import android.graphics.B ...