MySQL数据碎片的整理和分析

本文通过实验说明MySQL数据库在删除数据后产生的存储空间碎片及其对读取效率的影响,并介绍如何使用OPTIMIZETABLE命令来减少碎片。
MySQL具有相当多不同种类的存储引擎来实现列表中的数据存储功能。每当MySQL从你的列表中删除了一行内容,该段空间就会被留空。而在一段时间内的大量删除操作,会使这种留空的空间变得比存储列表内容所使用的空间更大。当MySQL对数据进行扫描时,它扫描的对象实际是列表的容量需求上限,也就是数据被写入的区域中处于峰值位置的部分。如果进行新的插入操作,MySQL将尝试利用这些留空的区域,但仍然无法将其彻底占用。这种额外的破碎的存储空间在读取效率方面比正常占用的空间要低得多。
以下实验举例说明:

C:\Users\duansf>mysql -uroot -p123456
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.5.13 MySQL Community Server (GPL)


Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.


Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.


Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql> 


创建一个测试库:


mysql> create database frag_test;
Query OK, 1 row affected (0.01 sec)


mysql> use frag_test;
Database changed
mysql> create table frag_test (c1 varchar(64));
Query OK, 0 rows affected (0.27 sec)


插入几行数据:
mysql> insert into frag_test values ('this is row 1');
Query OK, 1 row affected (0.21 sec)


mysql> insert into frag_test values ('this is row 2');
Query OK, 1 row affected (0.05 sec)


mysql> insert into frag_test values ('this is row 3');
Query OK, 1 row affected (0.03 sec)




现在我们进行碎片查看:
mysql> show table status from frag_test\G;
*************************** 1. row ***************************
           Name: frag_test
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 3
 Avg_row_length: 5461
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 10485760
 Auto_increment: NULL
    Create_time: 2016-03-17 16:36:04
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)


ERROR:
No query specified


删除一行,并再次检测:


mysql> delete from frag_test where c1 = 'this is row 2';
Query OK, 1 row affected (0.07 sec)


mysql> show table status from frag_test\G;
*************************** 1. row ***************************
           Name: frag_test
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 2
 Avg_row_length: 8192
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 10485760
 Auto_increment: NULL
    Create_time: 2016-03-17 16:36:04
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)


Data_free: 10485760 我们看到Data_free的值并没有减小


清理碎片试试:


mysql> optimize table frag_test;
+---------------------+----------+----------+-----------------------------------
--------------------------------+
| Table               | Op       | Msg_type | Msg_text
                                |
+---------------------+----------+----------+-----------------------------------
--------------------------------+
| frag_test.frag_test | optimize | note     | Table does not support optimize, d
oing recreate + analyze instead |
| frag_test.frag_test | optimize | status   | OK
                                |
+---------------------+----------+----------+-----------------------------------
--------------------------------+
2 rows in set (0.66 sec)


mysql> show table status from frag_test\G;
*************************** 1. row ***************************
           Name: frag_test
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 2
 Avg_row_length: 8192
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 9437184
 Auto_increment: NULL
    Create_time: 2016-03-17 16:36:04
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

Data_free: 9437184 清理碎片后,Data_free减小了。

“data_free”一栏显示出了我们删除第二行后所产生的留空空间。想象一下如果你有两万行指令的话,结果是什么样的。
以此推算,它们将耗费四十万字节的存储空间。现在如果你将两万条命令行删到只剩一行,列表中有用的内容将只占二十字节,
但MySQL在读取中会仍然将其视同于一个容量为四十万字节的列表进行处理,并且除二十字节以外,其它空间都被白白浪费了。

备注:
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。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15498/viewspace-2058947/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/15498/viewspace-2058947/

MySQL 数据库中表的碎片化是由于频繁的 `DELETE`、`UPDATE` `INSERT` 操作造成的。这些操作可能导致数据页中存在大量未使用的空间,从而影响性能存储效率。为了解决这一问题,可以采取以下几种方式进行碎片整理表空间优化。 ### 查看表的碎片情况 可以通过查询 `information_schema.TABLES` 来获取表的碎片信息。以下是一个常用的查询语句: ```sql SELECT ROW_FORMAT, TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH, MAX_DATA_LENGTH, DATA_FREE, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name' LIMIT 1; ``` 该查询将返回表的行格式、行数、数据长度、索引长度、最大数据长度、未使用空间以及使用的存储引擎。其中 `DATA_FREE` 字段表示表中未使用的空间大小,如果这个值较大,则说明该表可能存在较多的碎片[^1]。 ### 找出可释放空间较大的表 如果你想要找出数据库中可释放空间超过一定大小(例如 10MB)的表,可以使用以下查询语句: ```sql SELECT table_name, ROUND(data_length / 1024 / 1024) AS data_length_mb, ROUND(data_free / 1024 / 1024) AS data_free_mb FROM information_schema.tables WHERE ROUND(data_free / 1024 / 1024) > 10 ORDER BY data_free_mb DESC LIMIT 10; ``` 该查询将列出可释放空间超过 10MB 的最大 10 个表,并按照可释放空间从大到小排序[^2]。 ### 碎片整理方法 #### 1. 使用 `OPTIMIZE TABLE` 命令 `OPTIMIZE TABLE` 是一种简单有效的方式来整理表的碎片。它会重建表并释放未使用的空间,同时更新索引统计信息。适用于 MyISAM InnoDB 存储引擎。 ```sql OPTIMIZE TABLE your_table_name; ``` 执行该命令后,MySQL 会重建表并重新组织数据文件以减少碎片。对于 InnoDB 表,此操作还会压缩表(如果启用了 `innodb_file_per_table` 选项)[^1]。 #### 2. 使用 `ALTER TABLE` 命令 另一种方法是使用 `ALTER TABLE` 命令来重建表。这种方法适用于 InnoDB MyISAM 表。 ```sql ALTER TABLE your_table_name ENGINE = InnoDB; ``` 通过更改表的存储引擎(例如从 InnoDB 更改为 InnoDB,虽然看起来没有变化),MySQL 会自动重建表并释放未使用的空间。此方法也可以用来更改表的其他属性,例如字符集或行格式[^3]。 #### 3. 启用 `innodb_file_per_table` `innodb_optimize_point` 对于 InnoDB 表,建议启用 `innodb_file_per_table` 选项,这样每个表都会有自己的表空间文件。这使得碎片整理更加高效,因为你可以单独优化每个表而不影响整个数据库。 此外,还可以启用 `innodb_optimize_point` 选项,允许在特定的时间点自动进行表优化。 #### 4. 定期维护计划 为了保持数据库的良好性能,建议定期执行上述优化操作。可以根据业务需求设置一个维护窗口,在低峰期运行优化任务。例如,可以使用 `cron` 作业或 MySQL 事件调度器来自动化这一过程。 #### 5. 使用第三方工具 除了 MySQL 自带的命令外,还可以使用一些第三方工具来帮助管理优化表空间,例如 `pt-online-schema-change` `mysqldump` 结合 `source` 命令进行表重建。这些工具提供了更多的灵活性功能,适合大规模数据库环境。 --- ### 总结 MySQL 数据库中的碎片化问题可以通过多种方式进行处理。首先,通过查询 `information_schema.TABLES` 来识别哪些表存在较多的碎片;其次,使用 `OPTIMIZE TABLE` 或 `ALTER TABLE` 命令来整理碎片并释放未使用的空间;最后,建议定期进行表优化以维持数据库的性能。对于大型数据库,可以考虑使用第三方工具来提高效率灵活性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值