方案1:分库分表,读写分离 (不推荐)

对于这样的问题,平时我吗第一反应是分库分表,但是往往忽略了,分库分表带来的黑坑!

1. 跨库/跨表查询带来的问题,你可能要改业务代码,分库/分表查询后数据聚合问题

2.数据再次上去后,水平扩展与分片策略算法冲突导致数据正确落库问题

3. 需要中间件ProxySql完成从库的访问流量分发,调用链路变长,还要保证高可用,运维成本高

4. 现有Mycat /ShardingSphere不支持历史数据的自动分片,需要手动完成旧数据的处理

方案2:使用分布式数据 (推荐)

分布式数据库能解决分库分表最诟病的数据分片问题,能当成单个Mysql服务那样连接使用,我们不管数据任何分布存储,国产的分布式数据如TiDB、OceanBase、openGauss;但是分布式数据库部署成本相对要高不少,因为它们需要一些组件服务支持它调度从长远来看是性价比较高的。

方案3:冷热数据分离  (推荐)

冷热数据分离,一般只做到分表就行,可行性高,成本也是最低的方案;就是需要少量改动查询的代码,如果业务能接受不可查历史久远的数据,代码都不用动。就是冷热数据的分类需要根据自己业务自行判断,一般过了一年的数据认为是冷数据。

下面是Mysql冷热数据分离的具体操作流程:

核心思路:用 MySQL 视图(View)屏蔽冷热差异,程序只查一个“逻辑表”,冷热数据自动合并,完全无。

第1步:归档冷数据到 orders_archive 表

-- 1. 建归档表(结构同主表)
CREATE TABLE orders_archive LIKE orders;

-- 2. 迁移冷数据(按你的规则,比如1年前且状态完结)
INSERT INTO orders_archive 
SELECT * FROM orders 
WHERE create_time < '2025-04-01' 
  AND status IN ('completed', 'closed');

-- 3. 删除主表中的冷数据
DELETE FROM orders 
WHERE create_time < '2025-04-01' 
  AND status IN ('completed', 'closed');

第2步:创建统一查询视图

-- 创建视图,合并热表 + 冷表
CREATE VIEW orders_all AS
SELECT * FROM orders          -- 热数据(主表)
UNION ALL
SELECT * FROM orders_archive; -- 冷数据(归档表)

第3步:把原表名指向视图(关键!)

-- 重命名原表(备份)
RENAME TABLE orders TO orders_hot;

-- 把视图命名为原表名
RENAME TABLE orders_all TO orders;

现在你的程序还是 SELECT * FROM orders WHERE ...,完全不用改!

写入操作如何兼容?

因为视图不支持写入,所以写操作需要修改sql

// 修改前(所有操作都用 orders)
"INSERT INTO orders ...";
"UPDATE orders SET ...";

// 修改后(写操作用 orders_hot,读操作仍用 orders)
"INSERT INTO orders_hot ...";   // 只改这一行!
"UPDATE orders_hot SET ...";    // 只改这一行!
"SELECT * FROM orders ...";     // 不用改!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐