这可能不是文章,而是有关在MySQL中使用大型表的某些功能的简短说明。
写作的原因似乎是每天在表中增加一个新列。 但是事实证明,一切都不如预期的那么简单。
因此,有一天晚上,为了不打扰我们亲爱的客户,我们需要在表格中添加一列。
为了更清楚地说明表和基的特征:
- 桌子大小110Gb
- 行数:750万
- 存储引擎:InnoDB
- 根据主从方案连接了两个sql服务器,而master在SSD上,slave在HDD上
这似乎是添加列-Alter Table的明显解决方案。
alter table table_name add source varchar(32)
我们使用了它(是的,我们知道它很糟糕,但是在这种情况下,风险很小)。
结果非常不愉快:
- 在向导上,添加列的过程大约花费了一个小时(!)
- 在从属服务器上,它在主服务器上的过程结束后开始,并持续了大约8个小时(!!)
- 在更改表期间,数据复制(!!!)在从属服务器上完全停止
但是有一线希望:有一小点好处是,在添加了列之后,表的大小减少了10%。
在下面的图中,它清晰可见。
向导上的CPU负载图。
从站上的CPU负载图。
复制滞后。那些在战场上这样做的人有什么麻烦呢?
首先,在Alter Table期间,您无法将数据写入表(但可以读取)。 实际上,它取决于MySQL的版本,而后者则不取决于MySQL的版本,但是尽管如此,您仍需要了解您的版本到底能提供什么功能,以避免麻烦。
因此,
如果表很大,则不可用时间将很长 (与我们一样,使用SSD时需要一个小时,而在常规磁盘上则需要8个小时),这是您的客户不太可能期望的。
其次,就像我们的情况一样,在执行Alter Table的过程中,
所有表 (不仅是我们更改的表)的
同步都完全停止在从属服务器上。 因此,如果您在第二台服务器上的数据很关键并且应该是最新的,则可能会不做任何更新而造成所有后续后果。
我们在添加列时遇到的另一个非显而易见的问题(但这是另一次)-
需要额外的磁盘空间 。
事实是,对表的某些更改会从头开始重新创建表,因此您所需要的空间不会少于现有表。 分别对于大桌子,需要适度的空间。 根据文档,在与原始目录相同的目录中创建一个临时表。
另外,在执行各种Alter Table的过程中,所有更改都将写入日志文件,以便在更改之后,可以在执行操作的时间内滚动数据。 在这里,也可能会遇到不愉快的意外:如果表长时间更改,并且操作量很大,那么不仅磁盘空间可能会用完,而且SQL设置中指定的文件大小限制可能会超出。 在任何情况下,“在线DDL操作都会失败,并且未提交的并发DML操作会回滚”等待着您。
我们面临这样一个事实,即临时文件的目录很小,结果我们不得不重新定义
innodb_tmpdir 。
要查看变量当前指向的位置,可以执行以下操作:
select @@GLOBAL.innodb_tmpdir;
请记住,临时目录的大小可能也需要表+索引的大小。 通常,要有足够的空间。
为了不重复文档,请在
https://dev.mysql.com/doc/refman/5.7/zh-CN/innodb-online-ddl-space-requirements.html上阅读更多详细信息。
但是怎么做呢? 实际上,没有适合所有场合的配方。
可能的选项之一,就像我们对不重要的表所做的那样:
- 创建具有所需结构的新表
- 填写旧表中的字段
- 删除或重命名旧表
- 重命名新的
我重复一遍,这适用于非关键更新表。 同时避免复制阻塞。 应当牢记的是,必须以使复制继续进行的方式填充新表,并且由于它是按顺序运行的,因此您无法使用单个sql表达式来执行操作,因此必须将其分成几个小查询,在这些小查询之间将进行其他数据的复制。 在其他情况下,其他选择也是可能的,也许有人会分享评论。
UPD
Syavadee建议使用percona在线模式更改。 实际上,它以其他优点实现了上述算法。
UPD
Arheops建议启用并行复制/ gtid以解决复制问题。
好吧,偶然地,有时候,为了了解表有多大,表中有多少行,您需要做一些教导
select count(*) from table_name
但是,在大型和已加载的表上,这也不是最快的操作,尤其是当您有50万行或更多的行时。
因此,对于近似的体积估计,可以使用以下方法:
SHOW TABLE STATUS FROM express where name='table_name'
不幸的是,在InnoDB引擎上,结果大小可能相差50%(在我们的示例中,如上表所示,实际记录数约为750万,而该方法仅显示了500万),但这非常适合进行指示性估算。
仅此而已,我希望本文能帮助某人避免使用原本无害的SQL命令带来的麻烦。