innodb节省存储空间

时间:2016-11-05 16:44:54

标签: mysql innodb

我想问一下mysql innodb你建议什么样的小数据库?

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

大多数字符串都保存为utf8mb4。对于某些列,我可以使用latin1(我知道可能只有拉丁字符)。如果我将它们转换为latin1,你认为我可以节省很多空间吗?似乎这种变化也可以让你在搜索中获得性能提升。

我已经将具有大量文本的列定义为MEDIUMTEXT。如果我将该列定义为TEXT,您认为我应该节省一些空间吗? - 从我看到的这种类型就像VARCHAR(它只占用字符串的长度)

您还有其他建议吗?

数据库有超过3亿行,并存储在大约100G

由于

1 个答案:

答案 0 :(得分:1)

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

从MEDIUMTEXT更改为TEXT无济于事。此类列中的每个字符串都以可变长度存储,最多只能存储您存储的字符串所需的长度。 TEXT可以存储高达64KB的字符串,MEDIUMTEXT可以存储高达16MB的字符串。我想每个这样的字符串可能需要一个长度指示符,每个TEXT两个字节,每个MEDIUMTEXT三个字节。因此,您可以在整个数据库中每列最多节省300MB(甚至可能不会那么多)。这不会产生足够的差异。

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

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

为了节省空间,有些人用ROW_FORMAT=COMPRESSED声明了InnoDB故事,但这要求你使用每表文件。由于您已在全局表空间中拥有表,即使将表重组为每个表的文件,也不会缩小全局表空间。当您将表移动到自己的文件中时,它只会留下一个大部分为空的巨大全局表空间。这样只会让您的存储问题变得更糟。

我唯一可以建议您执行以下步骤。在你这样做时,没有人可以使用你的数据库。

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

    mysqldump ... | gzip -c > dump.sql.gz
    
  2. 停止你的mysqld进程。

  3. 删除整个全局表空间,即rm /var/lib/mysql/ibdata1,以及您可能仍然拥有的任何* .ibd文件。 当然,你应该先备份。
  4. 在/etc/my.cnf中启用innodb_file_per_table。同时启用innodb_file_format=Barracuda,具体取决于MySQL的版本。
  5. 启动你的mysqld进程。它会自动将全局表空间重新创建为一个新的小文件。
  6. 恢复您转储的表格。它们将被放入单独的InnoDB文件中,而不是全局表空间。
  7. 如有必要,请将每个表格改为使用ROW_FORMAT=COMPRESSED
  8. 这显然需要很长时间才能转储并重新加载300M行。这将花费数小时,在此期间您的数据库将无法使用。

    如果在执行此过程时无法使数据库不可用,则必须在副本上执行此操作,并且当过程完成且副本与主服务器同步时,您可以快速替换主人的复制品。在进行切换时,这仍然会导致短暂的服务中断,但速度很快。

    下次开始使用更大的数据库服务器存储卷。计划您需要的存储量并为其计划。

    重新评论,您已从MEDIUMTEXT更改为TEXT并节省了空间。

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

    表格也可以分段,偶尔重建一次可以回收一些空间。使用OPTIMIZE 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 |
    +-----------+
    

    我在MEDIUMTEXT中填充了2MB的数据,然后使用ALTER将列更改为TEXT。它不是简单地截断到可以放入TEXT列的64KB,而是将文本截断为零个字符。

    所以我希望您不要删除所有文本数据。