MySQL_共享表空间和独立表空间

共享表空间和独立表空间

学习检测

  1. 什么是共享表空间,什么事独立表空间?

  2. 数据删除流程(行和页)?

  3. 删除行和页的区别?

  4. 什么情况会产生空洞?具体说明

  5. online DDL重建表过程

  6. online DDL 锁的变化?

  7. online inplace 和copy的区别

  8. 删除数据释放表空间的方式?方式的区别

  9. 给表加全文索引和空间索引是阻塞的吗?

总结

  1. 数据和空间表结构定义村存放在一起的是共享表空间,单独存放的是独立表空间

  2. 行的删除只是标记为删除,空间为可用状态,页的删除的也是如此

  3. 行删除以后只限于复合范围条件的数据使用,页的删除可以应用到任何数据

  4. 增删改都会产生空洞,删除标记为删除会生成,改是删除和新增的过程也会生产,插入的时候,如果此行数据是页的最后一个,会产生页分裂和页合并行为,会生产

  5. 表A,创建临时文件,将A的数据导入临时文件,此时对A的操作记录在row log中,表A数据到临时文件写入完毕,将row log写入,用临时文件替换A中的数据

  6. online DDL 写锁降级为读锁,进行DDL操作,操作完毕,升级为写锁,释放锁

  7. online inplace 是在InnoDB层完成的,不涉及server,copy是强制copy一个表A的数据副本

    alter table t engine=innodb,ALGORITHM=inplace;
    alter table t engine=innodb,ALGORITHM=copy;
    
  8. alter table A engine = innoDB;(recreate操作) optimize table tal_name是recreate+anaylyze(统计基数)的操作

  9. 给表加全文索引和空间索引和阻塞增删改操作,读锁

MySQL5.5默认是共享表空间 ,5.6.6之后,默认是独立表空间。

查看表空间模式

show variables like ‘%innodb_file_per_table%’ ;
在这里插入图片描述

查看表空间信息

select * from information_schema.GLOBAL_VARIABLES where variable_name in (‘datadir’,‘innodb_data_file_path’,‘innodb_data_home_dir’,‘innodb_file_per_table’,‘innodb_open_files’);
在这里插入图片描述
innodb_file_per_table

表示表空间的类型。

datadir

数据存储位置

innodb_data_home_dir

为空值,则默认取值为:datadir参数的目录。

innodb_open_files

最多可打开的文件个数

innodb_data_file_path

表示共享文件的名称

file_name:file_size:auto_extend:max_size

file_name表示数据文件名称、file_size表示数据文件大小、auto_extend表示自动扩展、max_size表示最大大小

innodb_data_file_path=ibdata1:10M:autoextend:max:500M

ibdata1初始大小为10M、自动扩展且最大为500M。

多个标示符之间使用分号隔开,另外,只有最后一个文件能够使用autoextend属性。

数据删除流程

行记录删除只是标记为删除,空间大小不释放,只限于符合范围条件的数据

页记录删除是整个页标记为可用,可以插入任何数据值大小的值

行或者页的删除只是标记为删除,空间不会回收

delete insert update 都会造成空洞

页分裂造成空洞
在这里插入图片描述
假设,我们要删掉 R4 这个记录,InnoDB 引擎只会把 R4 这个记录标记为删除。如果之后要再插入一个 ID 在 300 和 600 之间的记录时,可能会复用这个位置。但是,磁盘文件的大小并不会缩小。

现在,你已经知道了 InnoDB 的数据是按页存储的,那么如果我们删掉了一个数据页上的所有记录,会怎么样?

答案是,整个数据页就可以被复用了。但是,数据页的复用跟记录的复用是不同的。

记录的复用,只限于符合范围条件的数据。比如上面的这个例子,R4 这条记录被删除后,如果插入一个 ID 是 400 的行,可以直接复用这个空间。但如果插入的是一个 ID 是 800 的行,就不能复用这个位置了。

而当整个页从 B+ 树里面摘掉以后,可以复用到任何位置。以图 1 为例,如果将数据页 page A 上的所有记录删除以后,page A 会被标记为可复用。这时候如果要插入一条 ID=50 的记录需要使用新页的时候,page A 是可以被复用的。

如果相邻的两个数据页利用率都很小,系统就会把这两个页上的数据合到其中一个页上,另外一个数据页就被标记为可复用。

进一步地,如果我们用 delete 命令把整个表的数据删除呢?结果就是,所有的数据页都会被标记为可复用。但是磁盘上,文件不会变小。

你现在知道了,delete 命令其实只是把记录的位置,或者数据页标记为了“可复用”,但磁盘文件的大小是不会变的。也就是说,通过 delete 命令是不能回收表空间的。这些可以复用,而没有被使用的空间,看起来就像是“空洞”。

页分裂造成的空洞

如果数据是按照索引递增顺序插入的,那么索引是紧凑的。但如果数据是随机插入的,就可能造成索引的数据页分裂。假设图 1 中 page A 已经满了,这时我要再插入一行数据,会怎样呢?
在这里插入图片描述
可以看到,由于 page A 满了,再插入一个 ID 是 550 的数据时,就不得不再申请一个新的页面 page B 来保存数据了。页分裂完成后,page A 的末尾就留下了空洞(注意:实际上,可能不止 1 个记录的位置是空洞)。

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

也就是说,经过大量增删改的表,都是可能是存在空洞的。所以,如果能够把这些空洞去掉,就能达到收缩表空间的目的。

而重建表,就可以达到这样的目的。

重建表

alter table A engine=InnoDB

5.5版本之前

新建一个与表 A 结构相同的表 B,然后按照主键 ID 递增的顺序,把数据一行一行地从表 A 里读出来再插入到表 B 中。

由于表 B 是新建的表,所以表 A 主键索引上的空洞,在表 B 中就都不存在了。显然地,表 B 的主键索引更紧凑,数据页的利用率也更高。如果我们把表 B 作为临时表,数据从表 A 导入表 B 的操作完成后,用表 B 替换 A,从效果上看,就起到了收缩表 A 空间的作用。

5.6版本之后

alter table A engine=InnoDB 重建表结构,去除空洞

在 MySQL 5.5 版本之前,这个命令的执行流程跟我们前面描述的差不多,区别只是这个临时表 B 不需要你自己创建,MySQL 会自动完成转存数据、交换表名、删除旧表的操作。
在这里插入图片描述
显然,花时间最多的步骤是往临时表插入数据的过程,如果在这个过程中,有新的数据要写入到表 A 的话,就会造成数据丢失。因此,在整个 DDL 过程中,表 A 中不能有更新。也就是说,这个 DDL 不是 Online 的。

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

online DDL 重建表流程

  1. 重建一个临时文件,扫描A主键的所有数据页

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

  3. 生成临时文件的过程中,将所有对A的操作记录在一个日志文件(rwo log)中,对应state2状态

  4. 临时文件生成后,jaingqilong日志文件中的操作应用到临时文件,得到一个逻辑数据上和A相同的数据文件,对应的就是图中state3的状态

  5. 用临时文件替换表A中的数据文件
    在这里插入图片描述
    可以看到,与图 3 过程的不同之处在于,由于日志文件记录和重放操作这个功能的存在,这个方案在重建表的过程中,允许对表 A 做增删改操作。这也就是 Online DDL 名字的来源。

online DDL过程

针对读写锁互斥的情况

session A 进行读 session B 进行写 会阻塞

session A进行写 sessionB 进行读 不会阻塞,因为 online ddl

1.拿MDL写锁

  1. 降级成MDL读锁
  2. 真正做DDL
  3. 升级成MDL写锁
  4. 释放MDL锁

1、2、4、5如果没有锁冲突,执行时间非常短。第3步占用了DDL绝大部分时间,这期间这个表可以正常读写数据,是因此称为“online ”

确实,图 4 的流程中,alter 语句在启动的时候需要获取 MDL 写锁,但是这个写锁在真正拷贝数据之前就退化成读锁了。

为什么要退化呢?为了实现 Online,MDL 读锁不会阻塞增删改操作

那为什么不干脆直接解锁呢?为了保护自己,禁止其他线程对这个表同时做 DDL。

而对于一个大表来说,Online DDL 最耗时的过程就是拷贝数据到临时表的过程,这个步骤的执行期间可以接受增删改操作。所以,相对于整个 DDL 过程来说,锁的时间非常短。对业务来说,就可以认为是 Online 的。

需要补充说明的是,上述的这些重建方法都会扫描原表数据和构建临时文件。对于很大的表来说,这个操作是很消耗 IO 和 CPU 资源的。因此,如果是线上服务,你要很小心地控制操作时间。如果想要比较安全的操作的话,我推荐你使用 GitHub 开源的 gh-ost 来做。

online 和inplace

说到 Online,我还要再和你澄清一下它和另一个跟 DDL 有关的、容易混淆的概念 inplace 的区别。

你可能注意到了,在图 3 中,我们把表 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 的。

如果说这两个逻辑之间的关系是什么的话,可以概括为:

DDL 过程如果是 Online 的,就一定是 inplace 的;

反过来未必,也就是说 inplace 的 DDL,有可能不是 Online 的。

截止到 MySQL 8.0,添加全文索引(FULLTEXT index)和空间索引 (SPATIAL index) 就属于这种情况

重建表的预留空间

在重建表的时候,InnoDB 不会把整张表占满,每个页留了 1/16 给后续的更新用。也就是说,其实重建表之后不是“最”紧凑的。假如是这么一个过程:将表 t 重建一次;插入一部分数据,但是插入的这些数据,用掉了一部分的预留空间;这种情况下,再重建一次表 t,就可能会出现问题中的现象。

optimize alter table-anaylyze 区别

从 MySQL 5.6 版本开始,alter table t engine = InnoDB(也就是 recreate)默认的就是上面图 4 的流程了;analyze table t 其实不是重建表,只是对表的索引信息做重新统计,没有修改数据,这个过程中加了 MDL 读锁;optimize table t 等于 recreate+analyze。

发布了48 篇原创文章 · 获赞 31 · 访问量 4556

猜你喜欢

转载自blog.csdn.net/qq_39787367/article/details/103861932