单表数据量过大查询速度慢解决方案
方案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 ..."; // 不用改!