mysql 碎片清理

本文通过具体实例解释了在MySQL中为何需要对使用了VARCHAR、TEXT或BLOB等数据类型的表进行碎片整理,以及如何使用OPTIMIZETABLE指令来实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在MySQL中,我们经常会使用VARCHARTEXTBLOB等可变长度的文本数据类型。不过,当我们使用这些数据类型之后,我们就不得不做一些额外的工作——MySQL数据表碎片整理。

那么,为什么在使用这些数据类型之后,我们就要对MySQL定期进行碎片整理呢?

现在,我们先来看一个具体的例子。在这里,我们使用如下SQL语句在MySQL自带的TEST数据库中创建名为DEMO的数据表并插入5条测试数据。

 
  1. --创建DEMO
  2. CREATE TABLE DEMO(
  3. id int unsigned,
  4. body text
  5. ) engine=myisam charset=utf8;
  6. --插入5条测试数据
  7. INSERT INTO DEMO VALUES(1, 'AAAAA');
  8. INSERT INTO DEMO VALUES(2, 'BBBBB');
  9. INSERT INTO DEMO VALUES(3, 'CCCCC');
  10. INSERT INTO DEMO VALUES(4, 'DDDDD');
  11. INSERT INTO DEMO VALUES(5, 'EEEEE');

然后我们以这5条测试数据为基础,使用如下INSERT INTO语句重复执行多次进行复制性插入。

INSERT INTO DEMO SELECT id, body FROM DEMO;

使用INSERT INTO语句多次插入产生总共约262万条数据使用INSERT INTO语句多次插入产生总共约262万条数据

众所周知,MySQL中MyISAM表的数据是以文件形式存储的,我们可以在MySQL存储数据的文件夹中找到数据库test目录下的demo.MYD文件。此时,我们可以看到demo.MYD文件的大小约为50MB。

demo.MYD文件约为50MBdemo.MYD文件约为50MB

此时,假如我们需要删除DEMO表中所有ID列小于3的数据(即1和2),于是我们执行如下SQL语句:

DELETE FROM DEMO WHERE id < 3

此时,我们可以看到DEMO表中的数据量只有原来的3/5:

删除后,只剩下157万条记录删除后,只剩下157万条记录

DEMO表中的现有数据量只有原来的3/5,按理说,这个时候demo.MYD文件的大小也应该只有原来的3/5左右。不过,我们再次查看demo.MYD文件时,却惊奇地发现该文件的大小一点都没有变!

删除数据后,demo.MYD的文件大小没有变化删除数据后,demo.MYD的文件大小没有变化

那么就究竟是怎么一回事呢?原来,在MySQL中,如果我们删除了表中的大量数据,或者我们对含有可变长度文本数据类型(VARCHARTEXTBLOB)的表进行了很多更改,不过被删除的数据记录仍然被保持在MySQL的链接清单中,因此数据存储文件的大小并不会随着数据的删除而减小。

当我们确定数据需要被清除掉时,那么这些数据就已经成了无用的数据,但是按照MySQL的处理方式,这些数据仍然会占用我们的磁盘空间,从而造成了极大的资源浪费。不仅如此,过大的数据文件还会导致MySQL执行相关数据操作时需要耗费更多的性能和时间。因此,对MySQL的某些数据表进行碎片整理是非常有必要的。

对MySQL进行碎片整理的方法非常简单,因为MySQL已经给我们提供了对应的SQL指令,这个SQL指令就是OPTIMIZE TABLE,其完整语法如下:

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE table_name1 [, table_name2] ...

从上面的语法描述中,我们可以得知,OPTIMIZE TABLE可以一次性对多个表进行碎片整理,只需要在OPTIMIZE TABLE后面接多个表名,并以英文逗号隔开即可。

此外,OPTIMIZE TABLE语句有两个可选的关键字:LOCALNO_WRITE_TO_BINLOG。在默认情况下,OPTIMIZE TABLE语句将会被记录到二进制日志中,如果我们指定了LOCALNO_WRITE_TO_BINLOG关键字,则不会记录。当然,一般情况下,我们也无需关注这两个关键字。

现在,我们就使用OPTIMIZE TABLE语句对刚才的DEMO表进行碎片整理。

对demo表进行碎片整理对demo表进行碎片整理

然后,我们再来查看demo.MYD文件,此时我们就会发现demo.MYD文件的大小已经减小到约为原来的3/5了。

碎片整理后demo.MYD文件的大小碎片整理后demo.MYD文件的大小

备注
1.MySQL官方建议不要经常(每小时或每天)进行碎片整理,一般根据实际情况,只需要每周或者每月整理一次即可。
2.OPTIMIZE TABLE只对MyISAM,BDB和InnoDB表起作用,尤其是MyISAM表的作用最为明显。此外,并不是所有表都需要进行碎片整理,一般只需要对包含上述可变长度的文本数据类型的表进行整理即可。
3.在OPTIMIZE TABLE运行过程中,MySQL会锁定表。
4.默认情况下,直接对InnoDB引擎的数据表使用OPTIMIZE TABLE,可能会显示「 Table does not support optimize, doing recreate + analyze instead」的提示信息。这个时候,我们可以用mysqld --skip-new或者mysqld --safe-mode命令来重启MySQL,以便于让其他引擎支持OPTIMIZE TABLE


转载:http://www.365mini.com/page/mysql-optimize-table.htm

<think>我们被要求回答关于MySQL碎片清理的问题。根据用户提供的引用,我们可以总结如下: 1. 引用[1]和[2]提供了查询表碎片的方法,主要查询`information_schema.tables`表中的`DATA_FREE`字段,该字段表示碎片空间(单位是字节)。 2. 引用[1]建议碎片空间大于1GB(或者根据实际情况,比如碎片占比>50%)时进行整理。 3. 清理碎片的方法:使用`ALTER TABLE tbl_name ENGINE=INNODB;`(对于InnoDB表)或者`OPTIMIZE TABLE tbl_name;`(注意:对于InnoDB表,OPTIMIZE TABLE实际上会被映射为ALTER TABLE ... FORCE,这相当于重建表并重新整理碎片)。 4. 引用[3]和[4]提到了另一种清理碎片的方法:通过导出导入数据的方式,即先导出部分数据(例如根据条件),然后导入。 需要注意的是,清理碎片操作(尤其是ALTER TABLE或OPTIMIZE TABLE)会锁表,因此在高并发场景下需要谨慎,最好在业务低峰期进行。另外,对于InnoDB表,如果使用的是独立表空间(每个表一个ibd文件),则可以通过重建表来释放空间给操作系统;如果是共享表空间,则空间只会还给InnoDB,而不会还给操作系统。 此外,引用[1]还提到官方建议不要频繁整理碎片,每周或每月整理一次即可。 下面我们将按照用户要求的结构化方式来回答。</think>### MySQL碎片清理方法 MySQL碎片是指数据文件中的空闲空间,主要由频繁的增删改操作导致。碎片会降低查询效率、增加磁盘占用。以下是清理方法: #### 1. **检测碎片** 使用系统表查询碎片情况: ```sql -- 查看碎片大于1GB的表(推荐) SELECT TABLE_SCHEMA, TABLE_NAME, ROUND(DATA_FREE/1024/1024/1024,2) AS free_GB FROM information_schema.TABLES WHERE DATA_FREE > 0 AND TABLE_SCHEMA NOT IN ('mysql','information_schema') HAVING free_GB > 1 ORDER BY free_GB DESC; -- 查看所有存在碎片的表 SELECT table_schema, table_name, data_free, ENGINE FROM information_schema.TABLES WHERE data_free > 0; ``` [^1][^2] #### 2. **清理方法** **方法1:ALTER TABLE重建(推荐)** ```sql ALTER TABLE 表名 ENGINE=INNODB; -- InnoDB引擎 ALTER TABLE 表名 ENGINE=MYISAM; -- MyISAM引擎 ``` * 原理:重建表结构并重组数据页 * 优点:操作简单,自动完成 * 注意:会锁定表,建议在业务低峰期操作[^1] **方法2:OPTIMIZE TABLE命令** ```sql OPTIMIZE TABLE 表名; ``` * 效果等同于`ALTER TABLE ... ENGINE=...` * InnoDB表实际执行的是`ALTER TABLE`重建[^1] **方法3:导出导入数据(超大表适用)** ```bash # 导出数据(带条件筛选) mysqldump -u用户 -p 数据库 表名 \ --where="update_time<='2023-01-01'" \ > /path/to/backup.sql # 导入数据 mysql -u用户 -p 数据库 < /path/to/backup.sql ``` [^3][^4] #### 3. **最佳实践** 1. **清理频率**:每周/月一次,避免频繁操作(每小时/天整理可能适得其反)[^1] 2. **触发条件**: - 碎片空间 > 1GB - 碎片占比 > 50% 3. **操作建议**: - 优先处理高频读写的大表 - InnoDB表建议使用`ALTER TABLE ... ENGINE=INNODB` - 操作前备份数据 - 在从库执行,再切换主从 #### 4. **碎片监控脚本** ```sql SELECT TABLE_NAME, TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH, DATA_FREE, ROUND((DATA_FREE/(DATA_LENGTH+INDEX_LENGTH+1))*100,2) AS frag_ratio FROM information_schema.TABLES WHERE TABLE_SCHEMA='your_db' AND DATA_FREE > 1024*1024*1024 -- 碎片>1GB ORDER BY frag_ratio DESC; ``` > **重要提示**:清理操作会锁表并消耗I/O资源,务必在维护窗口进行。对于GB级大表,建议分批处理(如按时间范围导出导入)[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值