文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

面试题:MySQL表删除一半数据,B+树索引文件会不会变小?

2024-12-03 03:42

关注

本文转载自微信公众号「微观技术」,作者Tom哥  。转载本文请联系微观技术公众号。

一张千万级的数据表,删除了一半的数据,你觉得B+树索引文件会不会变小?

(答案在文章中!!)

我们先来做个实验,看看表的大小是如何变化的?

做个实验,让数据说话

1、首先,在mysql中创建一张用户表,表结构如下:

  1. CREATE TABLE `user` ( 
  2.   `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  3.   `user_name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名'
  4.   `age` int(11) NOT NULL  COMMENT '年龄'
  5.   `address` varchar(128) COMMENT '地址'
  6.    PRIMARY KEY (`id`) 
  7. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='用户表'

2、造数据。用户表中批量插入1000W条数据

  1. @GetMapping("/insert_batch"
  2. public Object insertBatch(@RequestParam("batch"int batch) { 
  3.  
  4.     // 设置批次batch=100000,共插入 1000W 条数据 
  5.     for (int j = 1; j <= batch; j++) { 
  6.         List<User> userList = new ArrayList<>(); 
  7.         for (int i = 1; i <= 100; i++) { 
  8.             User user = User.builder().userName("Tom哥-" + ((j - 1) * 100 + i)).age(29).address("上海").build(); 
  9.             userList.add(user); 
  10.         } 
  11.         userMapper.insertBatch(userList); 
  12.     } 
  13.     return "success"

批量插入,每个批次100条记录,100000个批次,共1000W条数据。

3、查看表文件大小

索引文件大小约 595 M,最后修改时间 02:17

说明:

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

独享表空间存储方式使用.ibd文件来存放数据和索引,且每个表一个.ibd文件。

表数据既可以存在共享表空间,也可以是单独文件。通过innodb_file_per_table参数控制。MySQL 5.6.6 版本之后,默认是ON,这样,每个 InnoDB 表数据存储在一个以 .ibd为后缀的文件中。

4、删除 约500W条数据

  1. @GetMapping("/delete_batch"
  2. public Object deleteBatch(@RequestParam("batch"int batch) { 
  3.     for (int j = 1; j <= batch; j++) { 
  4.         List idList = new ArrayList<>(); 
  5.         for (int i = 1; i <= 100; i += 2) { 
  6.             idList.add((long) ((j - 1) * 100 + i)); 
  7.         } 
  8.         userMapper.deleteUser(idList); 
  9.     } 
  10.     return "success"

开始时user表有1000W条数据,删除若干后,目前剩余约 550W 条。

5、在删除约500W条记录后,再次查看表文件大小

索引文件大小约 595 M,最后修改时间 10:34

实验结论:

对于千万级的表数据存储,删除大量记录后,表文件大小并没有随之变小。好奇怪,是什么原因导致的?不要着急,接下来,我们来深入剖析其中原因。

数据表操作有新增、删除、修改、查询,其中查询属于读操作,并不会修改文件内容。修改文件内容的是写操作,具体分为有删除、新增、修改三种类型。

接下来,我们开始逐一分析。

删除数据

InnoDB 中的数据采用B+树来组织结构。如果对B+树存储结构不清楚的话,可以先看下我之前写的一篇文章,巩固下基础知识。

面试题:mysql 一棵 B+ 树能存多少条数据?

假如表中已经插入若干条记录,构造的B+树结构如下图所示:

删除id=7这条记录,InnoDB引擎只是把id=7这条记录标记为删除,但是空间保留。如果后面有id位于(6,19)区间内的数据插入时,可以重复使用这个空间。

上图,表示新插入一条id=16的记录。

除了记录可以复用外,数据页也可以复用。当整个页从B+树摘掉后,可以复用到任何位置。

比如,将page number=5页上的所有记录删除以后,该page标记为可复用。此时如果插入一条id=100的记录需要使用新页,此时page number=5便可以被复用了。

如果相邻两个page的利用率都很低,数据库会将两个页的数据合并到其中一个page上,另一个page被标记为可复用。

当然,如果是像上面我们做的实验那样,将整个表的数据全部delete掉呢?所有的数据页都会被标记为可复用,但空间并没有释放,所以表文件大小依然没有改变。

总结:delete命令只是把数据页或记录位置标记为可复用,表空间并没有被回收,该现象我们称之为”空洞“。

新增数据

如果是插入的数据是随机的非主键有序,可能会造成数据页分裂。

上图可以看到,假如page number=5的数据页已经满了,此时插入id=15的记录,需要申请一个新的页page number=6来保存数据。待页分裂完成后,page number=5的最后位置就会留下一个可复用的空洞。

相反,如果数据是按照索引递增顺序插入的,那么索引是紧凑的,不会出现数据页分裂。

修改数据

如果修改的是非索引值,那么并不会影响B+树的结构。

比如,更新id=7的其它字段值,主键id保持不变。整个B+树并没有发生结构调整。

但是,如果修改的内容包含了索引,那么操作步骤是先删除一个旧的值,然后再插入一个新值。可能会造成空洞。

分析发现,新增、修改、删除数据,都可能造成表空洞,那么有没有什么办法压缩表空间??

客官,请继续往下看

新建表

我们可以新建一个影子表B与原表A的结构一致,然后按主键id由小到大,把数据从表A迁移到表B。由于表B是新表,并不会有空洞,数据页的利用率更高。

待表A的数据全部迁移完成后,再用表B替换表A。

MySQL 5.5 版本之前,提供了一键命令,快捷式完成整个流程,转存数据、交换表名、删除旧表。

  1. alter table 表名  engine=InnoDB  

但是,该方案有个致命缺点,表重构过程中,如果有新的数据写入表A时,不会被迁移,会造成数据丢失。

Online DDL

为了解决上面问题,MySQL 5.6 版本开始引入 Online DDL,对流程做了优化。

执行步骤:

与新建表的最大区别,增加了日志文件记录和重放功能。迁移过程中,允许对表A做增删改操作。

 

来源:微观技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯