解决数据库越来越慢

117 阅读1分钟

解决海量数据导致存储系统慢的问题,思想非常简单,就是一个“拆”字,把一大坨数据拆分成 N 个小坨,学名叫“分片(Shard)”。拆开之后,每个分片里的数据就没那么多了,然后让查找尽量落在某一个分片上,这样来提升查找性能。

历史订单

image.png

把历史订单数据放到历史订单表中,迁移数据需要做好备份。

删除历史数据:

select max(id) from orders
where timestamp < SUBDATE(CURDATE(),INTERVAL 3 month);

delete from orders
where id <= ?
order by id limit 1000;

可以先通过一次查询,找到符合条件的历史订单中最大的那个订单 ID,然后在删除语句中把删除的条件转换成按主键删除,每次指定删除记录条数。

执行删除语句的时候,最好在每次删除之间停顿一会儿,避免给数据库造成太大的压力。

当 MySQL 删除一条记录的时候,只是找到记录所在的文件中位置,然后把文件的这块区域标记为空闲,然后再修改 B+ 树中相关的一些指针,完成删除。其实那条被删除的记录还是躺在那个文件的那个位置,所以并不会释放磁盘空间。

如果说我们数据库的磁盘空间很紧张,非要把这部分磁盘空间释放出来,可以执行一次 OPTIMIZE TABLE 释放存储空间。对于 InnoDB 来说,执行 OPTIMIZE TABLE 实际上就是把这个表重建一遍,执行过程中会一直锁表,也就是说这个时候下单都会被卡住,这个是需要注意的。另外,这么优化有个前提条件,MySQL 的配置必须是每个表独立一个表空间(innodb_file_per_table = ON),如果所有表都是放在一起的,执行 OPTIMIZE TABLE 也不会释放磁盘空间。

我们的系统可以接受暂时停服,最快的方法是这样的:直接新建一个临时订单表,然后把当前订单复制到临时订单表中,再把旧的订单表改名,最后把临时订单表的表名改成正式订单表。

大致执行语句如下:


-- 新建一个临时订单表
create table orders_temp like orders;


-- 把当前订单复制到临时订单表中
insert into orders_temp
  select * from orders
  where timestamp >= SUBDATE(CURDATE(),INTERVAL 3 month);


-- 修改替换表名
rename table orders to orders_to_be_droppd, orders_temp to orders;


-- 删除旧表
drop table orders_to_be_dropp

此文章为3月Day14学习笔记,内容来源于极客时间《后端存储实战课》