mysql分区表不自动加速查询,仅当where条件包含分区键触发分区裁剪时才减少i/o;否则扫描所有分区,性能更差;主键或唯一索引必须包含分区键,否则建表报错error 1503。

分区表必须带分区键查询,否则白建
MySQL的PARTITION BY RANGE本身不自动加速查询,关键在执行时能否触发「分区裁剪」。如果WHERE条件里没出现分区字段(比如只查status = 'paid',却没带create_time),优化器会扫描所有分区,性能反而更差。
- 必须确保所有高频查询都包含分区键,例如
WHERE create_time >= '2026-04-01' AND status = 'paid' - 主键或唯一索引必须包含分区键,建表时若漏掉会直接报错:
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function - 别用
YEAR(create_time)这种表达式分区——它无法利用索引,推荐用TO_DAYS(create_time)或直接存日期字符串并按范围切分
归档冷数据优先用 EXCHANGE PARTITION,不是 INSERT INTO ... SELECT
把旧分区数据迁走,最怕锁表和慢操作。EXCHANGE PARTITION是元数据级交换,毫秒完成;而INSERT INTO ... SELECT要读写全量数据,大表可能跑几小时,期间还可能阻塞写入。
- 目标表(如
orders_archive_2025)必须和原分区结构完全一致:字段顺序、类型、索引、引擎(都是InnoDB),否则报错ERROR 1731 (HY000) - 目标表不能有外键,也不能被其他表外键引用,否则交换失败
- 交换后原分区变空,但磁盘空间不会立刻释放——
DROP PARTITION只是删元数据,想真正缩文件得后续执行ALTER TABLE orders ENGINE=InnoDB(需确保innodb_file_per_table=ON)
冷数据别硬塞进主库,哪怕用了ARCHIVE引擎
ARCHIVE引擎压缩率高、写快读慢,看起来适合冷数据,但它不支持索引、事务、UPDATE/DELETE,且一旦表过大,SELECT COUNT(*)或全表扫描仍会拖垮主线程。真正的冷数据应该物理隔离。
- 温/冷数据建议拆到独立实例,硬件可降配(CPU/内存减半,用HDD盘),避免影响热数据的Buffer Pool命中率
- 跨实例查询用
FEDERATED或应用层双源路由,别依赖视图——视图下推能力弱,容易全表扫远端表 - 如果要用对象存储(如OSS/S3),必须通过ETL工具(如
pt-archiver)中转,MySQL自身无法直连;且迁移后需同步更新元数据或业务标记字段(如archived_at),否则应用层无法判断该查哪边
冷热边界不能只看时间,得看真实访问日志
按「3个月前算冷数据」是典型拍脑袋做法。实际中,某类订单可能90天后仍有售后查询;用户行为日志看似冷,但风控系统每天要扫最近半年的异常模式。冷热判断必须基于真实访问信号。
- 先在从库跑统计:
SELECT create_time, COUNT(*) FROM slow_log WHERE query_time > 1 AND sql_text LIKE '%orders%' GROUP BY DATE(create_time) ORDER BY COUNT(*) DESC - 结合应用埋点:在DAO层记录每个主键范围的QPS和P99延迟,识别长期
avg_latency > 500ms且qps 的数据段 - 冷数据迁移前务必验证:把候选数据集导出到测试库,模拟真实查询路径压测,确认延迟可接受再上线











