MySQL 表分区详解

MySQL 分区表是把一张大表按照规则拆分成多个物理小块(分区),逻辑上还是一张完整的表,对上层应用透明,不用改业务SQL。

核心目的:提升查询性能、降低维护成本、方便数据归档清理。

一、分区表基础概念

  1. 核心原理

逻辑层:一张完整的表,用户操作和普通表无区别

物理层:数据、索引分散存储在多个分区文件中,不同分区独立管理

分区键:用来划分数据的字段/表达式,是分区的核心

  1. 分区适用场景

表数据量极大(千万/亿级),单表IO压力大

按时间范围归档数据(日志、订单、流水表)

冷热数据分离,频繁查询热数据,冷数据单独存储

按地区、类别拆分数据,缩小查询扫描范围

  1. 不适合分区的场景

表数据量小,分区反而增加开销

频繁跨分区查询,会触发全分区扫描,性能下降

分区键频繁更新,会导致分区数据迁移,开销巨大

大量随机插入,分区不均匀导致热点分区

二、MySQL支持的分区类型

MySQL 5.1+ 支持4种主流分区,InnoDB、MyISAM 均支持:

  1. 范围分区 RANGE(最常用,时间分区首选)

按照字段值的连续范围划分分区,比如按时间、ID区间。

语法:

CREATE TABLE order(

id BIGINT,

create_time DATETIME

) ENGINE=InnoDB

PARTITION BY RANGE (TO_DAYS(create_time))(

PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')),

PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')),

PARTITION p_max VALUES LESS THAN MAXVALUE

);

特点:

适合时间维度数据,按月/按天分表

清理旧数据直接删除分区,速度极快(ALTER TABLE order DROP PARTITION p202601;)

必须有上限分区 MAXVALUE,否则超出范围数据无法插入

  1. 列表分区 LIST

按照字段的离散枚举值划分,比如按地区、业务线、状态。

CREATE TABLE user(

id INT,

city VARCHAR(20)

) ENGINE=InnoDB

PARTITION BY LIST (city)(

PARTITION p_north VALUES IN ('北京','天津','河北'),

PARTITION p_south VALUES IN ('广东','广西','海南'),

PARTITION p_east VALUES IN ('上海','江苏','浙江')

);

注意:MySQL8.0 之前 LIST 分区不支持多字段枚举,只能单个字段。

  1. 哈希分区 HASH

根据分区键的哈希值取模,均匀分散数据,避免数据倾斜。

CREATE TABLE goods(

id INT,

stock INT

) ENGINE=InnoDB

PARTITION BY HASH(id)

PARTITIONS 8; -- 分成8个分区

变种:线性哈希分区 LINEAR HASH,采用线性算法,分区扩容/缩容更高效,但数据分散性略差。

  1. 键分区 KEY

类似哈希分区,MySQL自动对分区键做哈希运算,支持多字段分区。

CREATE TABLE log(

id BIGINT,

user_id INT

) ENGINE=InnoDB

PARTITION BY KEY(id,user_id)

PARTITIONS 6;

  1. 复合分区(子分区)

先按范围分区,再在每个范围分区内做哈希/列表二次分区,适合超大表。

例:先按时间范围,再按用户ID哈希

CREATE TABLE big_log(

id BIGINT,

create_time DATETIME,

user_id INT

) ENGINE=InnoDB

PARTITION BY RANGE (TO_DAYS(create_time))

SUBPARTITION BY HASH(user_id)

SUBPARTITIONS 4(

PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')),

PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01'))

);

三、分区表关键语法操作

  1. 查看分区信息

-- 查看表分区状态

SELECT PARTITION_NAME,TABLE_ROWS,DATA_LENGTH,INDEX_LENGTH

FROM INFORMATION_SCHEMA.PARTITIONS

WHERE TABLE_SCHEMA='库名' AND TABLE_NAME='表名';

-- 查看分区定义

SHOW CREATE TABLE 表名;

  1. 新增分区(范围分区扩容)

ALTER TABLE order

REORGANIZE PARTITION p_max INTO (

PARTITION p202603 VALUES LESS THAN (TO_DAYS('2026-04-01')),

PARTITION p_max VALUES LESS THAN MAXVALUE

);

  1. 删除分区(清理历史数据)

ALTER TABLE order DROP PARTITION p202601;

风险:删除分区会直接删除对应数据,不可逆,InnoDB会立即释放磁盘空间。

  1. 合并/拆分分区

-- 拆分分区

ALTER TABLE t REORGANIZE PARTITION p_old INTO (PARTITION p1 VALUES LESS THAN 1000,PARTITION p2 VALUES LESS THAN 2000);

-- 合并分区

ALTER TABLE t REORGANIZE PARTITION p1,p2 INTO (PARTITION p_old VALUES LESS THAN 2000);

  1. 移除分区(变回普通表)

ALTER TABLE 表名 REMOVE PARTITIONING;

四、分区表工作原理:分区裁剪 Partition Pruning

这是分区表性能提升的核心机制。

当SQL的WHERE条件命中分区键时,MySQL优化器会只扫描符合条件的分区,跳过无关分区,大幅减少IO。

示例:

SELECT * FROM order WHERE create_time BETWEEN '2026-02-01' AND '2026-02-28';

优化器只会扫描 p202602 分区,不会扫描其他月份分区。

注意:如果分区键函数写法不对,会导致分区裁剪失效,全表扫描:

错误:WHERE DATE(create_time) = '2026-02-01'(函数作用在分区键上,优化器无法预判)

正确:WHERE create_time >= '2026-02-01' AND create_time < '2026-03-01'

五、分区表索引机制

分区索引:每个分区拥有独立的索引文件,索引是分区级别的,不是全局索引

普通二级索引:只在当前分区内生效,查询跨分区时需要扫描所有分区索引

InnoDB 分区表:主键必须包含分区键,否则创建报错(强制要求)

原因:InnoDB 聚簇索引结构,分区依赖主键定位数据,主键必须携带分区键

唯一索引:唯一索引也必须包含分区键,否则无法创建

六、分区表优缺点

优点

大幅提升查询性能,分区裁剪减少扫描数据量

历史数据清理极快,DROP PARTITION 毫秒级,比DELETE高效上万倍

冷热数据分离,热分区常驻内存,冷分区落地磁盘

单表数据量突破单文件大小限制,分散磁盘IO压力

缺点

分区数量不宜过多,建议单表分区控制在100个以内,元数据管理开销变大

跨分区查询、JOIN分区表性能较差,会触发多分区扫描

分区键设计不合理会导致数据倾斜,某个分区过大,失去分区意义

运维成本提升,需要定期规划分区扩容、归档策略

部分MySQL工具对分区表兼容性一般,备份、迁移需要特殊处理

七、生产最佳实践

优先RANGE时间分区:订单、日志、流水90%场景用按月/按天分范围分区

分区键尽量使用原生字段,避免复杂函数,保证分区裁剪生效

主键、唯一索引必须包含分区键,避免建表报错

提前规划分区,不要等到数据溢出MAXVALUE再扩容

冷热分离:冷分区可以单独设置存储引擎、磁盘介质

禁止频繁更新分区键字段,会触发分区数据迁移,产生大量IO

分区数量控制:单表分区50~100个最佳,不要超过200个

备份:分区表建议用物理备份(xtrabackup),逻辑备份会导出全表数据

八、常见坑点

分区键使用函数(如YEAR(create_time)),部分条件下裁剪失效

InnoDB分区表主键必须包含分区键,新手极易踩坑

LIST分区不能插入枚举外的数据,会报错

HASH分区数据不均匀,热点分区性能瓶颈

删除分区不可逆,生产环境务必先备份分区数据

分区表不支持外键约束(InnoDB分区表禁用外键)

相关推荐
迷茫的大专生4 小时前
服务器部署与 MySQL 运维学习笔记:从 Ansible 到高可用与性能优化
mysql·nginx·ansible·mysql优化·keepalive
Lyra_Infra5 小时前
从 MySQL 到达梦:一次信创隔离环境里的数据库迁移踩坑实录
数据库·后端·mysql
泡茶喝茶写代码6 小时前
量化数据开发实战系列(第 25 篇):基金基础接口实战:基金列表、ETF-LOF 分类、基金概况、净值数据
java·数据库·人工智能·python·mysql
worilb7 小时前
Win下使用同一套MySQL创建第二个独立实例
mysql
风哥2号8 小时前
数据库教程FGMT40‑MySQL性能优化之性能基准测试
数据库·mysql
葡萄成熟时 !8 小时前
MySQL 全套学习笔记(JDBC+连接池)
mysql
梦帮科技9 小时前
一次性会员支付系统的可靠性设计:幂等、金额校验、Webhook 与链上确认
人工智能·神经网络·mysql·区块链·建造者模式·合成复用原则·加密货币
初願致夕霞9 小时前
MySQL_事务(MVCC机制详解)
数据库·mysql
geovindu9 小时前
sql: Data Modeling Patterns using mysql
sql·mysql·设计模式·数据库开发
今年下半年9 小时前
mysql数据库备份详细操作流程
学习·mysql