You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
By clicking “Sign up for GitHub”, you agree to our
terms of service
and
privacy statement
. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
随着业务快速增长,MySQL 数据量不断增加,会带来如下两个问题:
磁盘空间吃紧
:数据库数据最终将会保存在本地磁盘中,数据记录越多,磁盘占用空间就会越多,对应剩余可用空间就会越少。
查询效率降低
:MySQL 的 InnoDB 存储引擎的存储结构是 B+ 树,查找的时间复杂度是 O(log n)。随着数据量的增大,B+ 树自然也会变的很大,查找效率也会随之下降。
所以,解决海量数据导致存储系统慢的问题,一般思路就是进行数据拆分,即
分片
。拆开之后,每个分片里的数据就没那么多了,然后让查找尽量落在某一个分片上,这样来提升查找性能。
当单表的数据太多,多到影响性能的时候,首选的方案是:
归档历史数据
。
数据归档的解决思路非常简单,就是将生产库的数据转移到拥有相同表结构的数据库中,通过减少生产库记录数量,从而提高数据查询等操作的效率。
数据归档分为三个流程:
创建一个新的数据库作为归档库,然后在归档库创建与生产库相同的表;
不断查询生产库数据记录,同步复制到归档库;
生产库删除已经复制的数据记录;
数据归档需要考虑的问题:
确定需要归档的数据范围;
确定归档的执行方案:使用工具归档(pt-archiver)、自定义程序进行归档;
确定数据归档后带来的问题的预案;
归档需要考虑的问题
1. 生产库备份
在进行数据归档之前,一定要确保生产库的数据进行了备份。如果在归档过程中出现一些意想不到的问题,可以使用备份数据进行还原。
2. 何时进行归档
数据归档过程需要不断的读写生产库,这个过程将会大量使用的网络、IO。为了防止对线上业务造成压力,数据归档一般只在业务低峰期执行。另外,我们需要尽可能调优数据,尽量降低对线上业务的影响。
3. 删除已复制数据
数据归档之后,将会删除生产库的数据,这些数据删除之后,将会造成数据空洞。即数据删除之后,表空间并未及时的释放,当长时间没有新的数据填充,会造成空间浪费的情况。所以数据删除之后,需要及时优化数据空洞,释放这些被浪费的空间。
4. 历史数据还原
数据归档之后,生产库就会缺失这部分数据,如果业务上正好需要使用这些数据,那就会造成业务上异常。所以,我们需要提供数据
逆向接口
,反向将归档数据库的记录重新还原到生产库。
5. 数据一致性问题
如果在进行数据归档的过程中,生产库中已复制的数据存在更新操作,那么会造成归档库与生产库的数据出现不一致的情况。所以,在进行数据归档时,需要保证历史数据没有更新操作。
如何删除已复制数据
还有一个很重要的细节问题:如何从原表中删除已经迁走的历史数据?直接执行一个删除历史数据的 SQL 行不行?比如:
DELETE FROM orders WHERE createTime < SUBDATE(CURDATE(),INTERVAL 3 month);
这样肯定是不行,如果删除的数据量比较大,会造成 SQL 语句占用时间长,锁的时间也比较长(即大事务),影响数据库性能;
而正确的方式是进行
多次分批删除
,并且最好在
每次删除之间停顿一会儿
,避免给数据库造成太大的压力。
DELETE FROM orders WHERE createTime < SUBDATE(CURDATE(),INTERVAL 3 month) ORDER BY id LIMIT 1000;
由于会对原表已归档的数据进行删除,会造成数据空洞,也就是
表碎片
。所以需要定期对表碎片进行清理,即重建表,以释放磁盘空间。
我们可以使用
alter table A engine=InnoDB
命令来重建表。重建表的过程中,索引也会重建,这样表数据和索引数据都会更紧凑,不仅占用磁盘空间更小,查询效率也会有提升。在 MySQL 8.0.26 或 8.0.29 这些高版本的数据库,执行此命令时,加锁时间很短,基本不会阻塞增删改操作。