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分区表禁用外键)

相关推荐
hasty6 小时前
policy.xml 在,不代表策略生效:ImageMagick 补丁给安全配置验收的提醒
xml·mysql·安全
晚风叙码12 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
做运维的阿瑞13 小时前
SQL 面试高频:用户、商品、订单三表查询全解析
数据库·sql·mysql
CJi0NG14 小时前
【自用】MySQL - 语法:DDL、DML、DQL、DCL
数据库·mysql
一技安身14 小时前
【mysql】Windows MySQL 8.4.10 绿色免安装喂饭教程
windows·mysql·adb
斯内普吖15 小时前
(开源)宠物饲养系统实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源·宠物
ao-weilai15 小时前
MySQL数据库:表约束
数据库·mysql·adb
FYKJ_201018 小时前
springboot心理健康管理系统86254-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·mysql·django·课程设计
做运维的阿瑞18 小时前
MYSQL从语义到执行计划:UNION、EXISTS、IN 的深度辨析
数据库·sql·mysql
小马同学-1 天前
MySQL主从复制和读写分离
数据库·mysql