mysql - innodb节省存储空间

标签 mysql innodb

我想询问mysql innodb,对于建议使用较小的数据库,您有何建议?

我没有innodb_file_per_table,但是我不需要回收空间(这很高兴看到我能够节省多少空间)。

大多数字符串都保存为utf8mb4。对于某些列,我可以使用latin1(我知道只能有拉丁字符)。您认为将它们转换为latin1可以节省很多空间吗?看来,这种变化也应该使您的搜索性能有所提高。

我将具有大量文本的列定义为MEDIUMTEXT。如果我将该列定义为TEXT,您是否认为应该节省一些空间? -从我看来,这种类型的行为类似于VARCHAR(它仅占用字符串的长度)

您还有其他建议吗?

该数据库有3亿多行,存储在大约100G中

谢谢

最佳答案

更改字符集将无济于事。使用utf8或utf8mb4时,每个字符都存储在可变数量的字节中。可以存储在单个字节中的字符以这种方式存储。

从MEDIUMTEXT更改为TEXT将无济于事。这样的列中的每个字符串都以可变长度存储,最多不超过您存储的字符串所需的长度。 TEXT最多可以存储64KB的字符串,MEDIUMTEXT最多可以存储16MB的字符串。我想每个这样的字符串可能需要一个长度指示符,即每个TEXT两个字节,每个MEDIUMTEXT三个字节。因此,在整个数据库中,每列最多可以节省300MB(甚至可能不多)。这不会产生太大的变化。

您可以找出表空间中有多少可用空间。运行SHOW TABLE STATUS LIKE 'sometable',其中“ sometable”是表空间中任何表的名称。

返回的字段之一是data_free。这是表空间中的可用空间(以字节为单位)。当您在同一个全局表空间中有多个表时,每个表都报告相同的值。这并不意味着您的可用空间就是所有这些数字的总和,实际上是在每个表状态中重复的一个可用空间。

为了节省空间,有些人用ROW_FORMAT=COMPRESSED声明了InnoDB故事,但这要求您使用每表文件。因为您已经在全局表空间中拥有表,所以即使您将表重组为每表文件,它也不会缩小全局表空间。当您将表移动到它们自己的文件中时,它将只留下一个巨大的全局表空间,该空间通常是空的。因此,这只会使您的存储问题更加严重。

我唯一可以建议的就是您执行以下步骤。执行此操作时,没有人可以使用您的数据库。


转储InnoDB表中的所有数据,如有必要,将转储的输出保存到另一个卷。哪里有空间。您可以像这样压缩转储的输出:

mysqldump ... | gzip -c > dump.sql.gz

停止mysqld进程。
删除整个全局表空间(即rm /var/lib/mysql/ibdata1)以及您可能仍然拥有的所有* .ibd文件。当然,您应该先备份。
在/etc/my.cnf中启用innodb_file_per_table。还要启用innodb_file_format=Barracuda,具体取决于MySQL的版本。
启动您的mysqld进程。它将自动将全局表空间重新创建为一个新的小文件。
恢复您转储的表。它们将被放入单个InnoDB文件中,而不是全局表空间中。
如有必要,请更改每个表以使用ROW_FORMAT=COMPRESSED


显然,转储和重新加载300M行需要很长时间。这将花费许多小时,并且您的数据库在这段时间内将无法使用。

如果执行此过程时不能使数据库不可用,则必须在副本上进行操作,并且当该过程完成且副本与主数据库同步时,可以快速将副本替换为大师。进行切换时,这仍然会导致服务短暂中断,但是很快。

下次从更大的数据库服务器存储量开始。计划所需的存储量并进行规划。



关于您的评论,您从MEDIUMTEXT更改为TEXT,并节省了空间。

INFORMATION_SCHEMA中的大小(与SHOW TABLE STATUS报告的大小相同)仅是估计值,它们可能已过时,也可能过时。偶尔运行ANALYZE TABLE是更新统计信息的一种方式。

一个表也可以被分割,不时地重建它可以回收一些空间。使用优化表。

另一种可能性是您的MEDIUMTEXT列实际上存储的文本字符串比TEXT列中存储的文本字符串长,而您的ALTER TABLE会截断它们。

这是一个示范:

mysql> create table m ( m mediumtext);

mysql> insert into m set m = repeat('X', 1024*1024*2);
Query OK, 1 row affected (0.05 sec)

mysql> select length(m) from m;
+-----------+
| length(m) |
+-----------+
|   2097152 |
+-----------+

mysql> alter table m modify column m text;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select length(m) from m;
+-----------+
| length(m) |
+-----------+
|         0 |
+-----------+


我用2MB数据填充了MEDIUMTEXT,然后使用ALTER将列更改为TEXT。它并没有简单地将其截断为TEXT列中的64KB,而是将文本截断为零个字符。

因此,我希望您不只是擦除所有文本数据。

关于mysql - innodb节省存储空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40440725/

相关文章:

mysql - Nodejs Mysql 优化查询

php - 每次尝试登录或按登录时,我都卡在运行方法中

mysql - HSQLDialect 到 MySQL5InnoDBDialect、Hibernate

mysql - 为什么不使用键的最左边子集来优化此 ORDER BY?

MySQL性能

MySQL 事件记录查询忽略大小写

javascript - Jquery 不将 html 传递到 iframe

mysql - 如何在vb.net中备份mysql数据库

mysql - 有没有更简单的方法来实现这种用户消息传递方式?

php - MyISAM 的意外双插入