从InnoDB表中删除和回收空间


14

我有一个700GB的InnoDB表,我不会再写入任何数据(只能读取)。我想删除它保存的旧数据并回收该磁盘空间(因为我快用完了)。删除部分非常简单,因为我有一个自动增量主索引,因此我可以使用它对块进行迭代,然后删除行,但这不会让我退缩。我认为OPTIMIZE TABLE会,但是在700GB的桌子上可能会永远占用,所以我有没有忽略其他选择?

由RolandoMySQLDBA编辑

假设您的表是mydb.mytable,请运行以下查询并将其发布在此处,以便您确定表收缩所需的磁盘空间:

SELECT
    FORMAT(dat/POWER(1024,3),2) datsize,
    FORMAT(ndx/POWER(1024,3),2) ndxsize,
    FORMAT((dat+ndx)/POWER(1024,3),2) tblsize
FROM (SELECT data_length dat,index_length ndx
FROM information_schema.tables WHERE
table_schema='mydb' AND table_name='mytable') A;

如果允许,我们还需要查看表结构。

由Noam编辑

这是查询的输出:

datsize ndxsize tblsize
682.51 47.57 730.08

这是表格结构(SHOW CREATE TABLE

`CREATE TABLE `mybigtable` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,  
  `created_at` datetime NOT NULL,  
  `tid` bigint(20) NOT NULL,  
  `text` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
  `ft` tinyint(1) NOT NULL,  
  `irtsd` bigint(20) NOT NULL,  
  `irtuid` int(11) NOT NULL,  
  `rc` int(11) NOT NULL,  
  `r` tinyint(1) NOT NULL,  
  `e` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,  `timezone` varchar(5) NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `uid_tid` (`uid`,`tid`)) ENGINE=InnoDB AUTO_INCREMENT=2006963844 DEFAULT CHARSET=utf8`

您是否有另一个磁盘卷仅可捕获数据???
RolandoMySQLDBA 2014年

@RolandoMySQLDBA我可以挂载外部硬盘驱动器。这算吗?
2014年

@RolandoMySQLDBA,但是当然想要删除一些空间而无需再有700GB的选项
Noam

@RolandoMySQLDBA多余的磁盘大小是否会导致性能问题?
阿里斯(Aris)'18年

@Aris可能取决于磁盘及其查找时间。如今,大多数磁盘现在性能更好,但是如果您的表中有大量稀疏的磁盘空间,那么浪费周期(甚至快得很快)是有好处的。对于通常固定为16K块的InnoDB尤其如此。如果内部碎片为16K块,则可能要使用ALTER TABLE ... ENGINE=InnoDB;(如果有足够的空间进行碎片整理)对表进行碎片整理。大多数人只对他们的高速SSD感到满意,不再担心。
RolandoMySQLDBA '18年

Answers:


21

这是一个很好的问题。您有几种解决方案,但您的表很大,因此没有一个会很痛苦的:)

您有三种“缩小” InnoDB表的解决方案:

1.优化表

您可以使用OPTIMIZE TABLE前面提到的方法,但是您应该注意innodb_file_per_table变量:

mysql> show variables like "innodb_file_per_table";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)

让我解释:

如果有OPTIMIZE TABLEInnoDB表,则锁定该表,将数据复制到新的干净表中(这就是为什么缩小结果的原因),删除原始表并使用原始名称重命名新表。这就是为什么您需要在磁盘上使表的容量增加一倍的原因(在操作过程中,您将需要2x700GB)。

当您在innodb_file_per_table = ON时。所有表都有正确的数据文件。因此,该OPTIMIZE语句将在操作完成后创建一个新的数据文件(〜700GB),MySQL将删除原始文件并重命名新文件(因此,最后700GB的数据(可能会减少,可能会减少),可能会更少)操作期间生成的将被释放)

当您在innodb_file_per_table = OFF时。所有数据都进入一个数据文件:ibdata。该文件具有特殊的可悲性,无法缩小。因此,在此OPTIMIZE过程中,将创建新表(接近700GB),但是即使在拖放和重命名操作(以及OPTIMIZE阶段结束)之后,您的ibdata也不会释放〜700GB,因此您希望释放一些数据,但您有700GB还有,很酷吗?

2.更改表

您还可以使用一条ALTER TABLE语句,该语句的ALTER TABLE工作方式与相同OPTIMIZE TABLE。您可以使用:

ALTER TABLE myTable EGINE=InnoDB;

3. ALTER TABLE(在线)

的问题OPTIMIZE,并ALTER TABLE使得其在运行过程中锁定表。您可以使用Percona工具:pt-online-schema-change(来自Percona Toolkit:链接 )。pt-online-schema ...将使用触发器和临时表构造机制,您可以在操作期间允许原始表进行读写。我在生产中使用了这个工具,因为ALTER它非常酷。

请注意,您应该已经FOREIGN KEY引用了表FK并触发了产生混乱的风险。要检查此先决条件,请查询:

mysql> SELECT COUNT(*) FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE REFERENCED_TABLE_NAME = "myTable";
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0.04 sec)

这是我使用pt-online-schema-change的方法:

pt-online-schema-change --alter "ENGINE=InnoDB" D=myBase,t=myTable --user --ask-pass

请注意,对于此解决方案,我对innodb_file_per_table的注释也为true。

4. mysqldump

最后一种解决方案是从转储中重新创建所有数据库。非常长,但效率很高。注意,这是“缩小” ibdata文件的唯一解决方案。

最高


另外在percona工具的在线alter table选项中,我是否需要700GB的可用磁盘空间?
2014年

是的,在线pt只是使用一些机制来在线进行ALTER,但无论如何它都会使ALTER成为可能。
Maxime Fouilleul 2014年

@MaximeFouilleul多余的磁盘大小会引起性能问题吗?
阿里斯(Aris)'18年

1

如果磁盘空间不足,我建议您像使用pt-online-schema-change(ONLINE)建议的Max一样。我在相同的情况下使用较小的表(200GB),并且选择同时做一些压缩。与此类似的东西应该起作用:

pt-online-schema-change --alter="ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4" D=myBase,t=myTable --user --ask-pass

仅当您使用梭子鱼文件格式和表的COMPACT格式时,这才有效。另外,您必须启用innodb_file_per_table。这可能会使表的大小惊叹不已,尤其是在文本很多且使用较小的KEY_BLOCK_SIZE(例如8K甚至4K,默认值为16K)的情况下。您还可以在其他博客上查看关于此问题的多个基准测试可以为您带来多少空间,但是MySQL文档宣传的是25%到50%(对我来说这几乎是90%)。

请注意,这也会影响执行SELECT时的性能(来自MySQL文档):

因此,在任何给定时间,缓冲池都可能包含页面的压缩形式和未压缩形式,或者仅包含页面的压缩形式,或者都不包含。

当不在缓冲池中时,MySQL还必须解压缩数据。所以要当心。

就我而言,这确实很好。我有很长的文字。200GB变为26GB。表演没有改变。

有关更多详细信息,请查看以下链接:

https://dev.mysql.com/doc/refman/5.5/zh-CN/innodb-compression-usage.html

https://dev.mysql.com/doc/refman/5.5/zh-CN/innodb-compression-internals.html

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.