MariaDB按月分区:char类型ID+日期列做主键是否可行?
关于MySQL大表按月分区的主键选择方案分析
针对你提到的2000万行interaction表的分区需求,结合MySQL分区规则和文档要求,下面分析两种主键方案的优劣:
方案一:使用id(char(36)) + created_at作为复合主键
可行但存在明显缺陷
- 不符合文档要求:明确要求主键是「自增ID+日期列」,而当前
id是UUID类型的字符串,并非自增整数,直接用它组合created_at会违反文档规范,后续可能带来合规或审计问题。 - 索引成本高:char(36)的UUID加上datetime类型的
created_at,复合主键的长度远大于整数类型,会导致主键索引占用更多磁盘空间,2000万行的情况下,索引体积会比整数主键大几倍,直接影响查询和写入性能。 - 插入性能差:UUID是无序值,即使组合了
created_at,主键索引的排序前缀仍是随机的UUID,插入时会频繁触发索引页的分裂和随机IO,大表批量插入时性能衰减明显,还会加剧索引碎片化。
方案二:新增自增列+created_at作为复合主键
更优且符合规范的选择
- 满足文档要求:新增的自增整数列(如
auto_id,建议用BIGINT避免溢出)+created_at的组合完全匹配「自增ID+日期列」的主键要求。 - 性能与存储优势:自增整数(8字节)+ datetime(8字节)的复合主键长度仅为UUID方案的一半左右,主键索引占用空间大幅减少,查询时的IO开销更低,插入时因自增列有序,索引页是顺序写入,碎片化程度极低,大表写入性能更稳定。
- 分区裁剪效率高:分区键
created_at包含在主键中,查询时只要指定created_at范围,MySQL能高效裁剪掉无关分区,配合有序的自增主键,范围查询和索引扫描的效率都会更高。 - 业务兼容友好:可以保留原
id列并设置为唯一索引,业务代码无需大规模修改,依然可以通过原id进行单条记录的查询,只需要在分区相关操作中使用新的复合主键。
实施注意事项
- 2000万行的大表修改表结构,禁止直接用ALTER TABLE,建议使用pt-online-schema-change或gh-ost等在线DDL工具,避免锁表影响业务。
- 分区策略建议用RANGE分区,基于
YEAR(created_at)*100 + MONTH(created_at)的值来划分月度分区,例如:
CREATE TABLE `interaction_new` ( `auto_id` bigint(20) NOT NULL AUTO_INCREMENT, `id` char(36) NOT NULL, `tenant_id` int(11) NOT NULL, `receiver_user_id` int(11) NOT NULL, `sender_user_id` int(11) NOT NULL, `type` varchar(50) NOT NULL, `created_at` datetime NOT NULL, `is_read` tinyint(4) NOT NULL, `updated_at` datetime DEFAULT NULL, PRIMARY KEY (`auto_id`, `created_at`), UNIQUE KEY `uk_id` (`id`), KEY `receiver_user_id_index` (`receiver_user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 PARTITION BY RANGE (YEAR(created_at)*100 + MONTH(created_at)) ( PARTITION p202401 VALUES LESS THAN (202402), PARTITION p202402 VALUES LESS THAN (202403), -- 按需添加历史和未来分区 PARTITION p_future VALUES LESS THAN MAXVALUE );
内容的提问来源于stack exchange,提问作者mmac-rio89
相关产品推荐
相关产品推荐

