4. 分区类型详解

分区表并不是“把大表随便切成几块”,而是按照明确的分区键与分区策略,把数据行映射到不同的物理段中。不同分区类型决定了数据如何分布、查询如何裁剪、维护如何操作,也直接决定了性能优化与回滚的难易程度。本节围绕范围分区、列表分区、哈希分区和复合分区,讲清原理、适用场景与常见误区。

一、核心原理:分区键如何决定数据落点

无论哪种分区类型,数据库在插入数据时都会计算分区键,并根据分区定义判断该行应落入哪个分区。查询时,优化器若能根据 WHERE 条件推导出只涉及部分分区,就会进行分区裁剪,减少扫描范围。因此,分区类型的选择本质上是在回答两个问题:数据按什么维度切分最自然?查询条件最常命中哪个维度?

  • 范围分区:按连续区间切分,如时间、ID 段、金额区间。
  • 列表分区:按离散枚举值切分,如地区、状态、租户类型。
  • 哈希分区:按哈希函数打散,追求均匀分布,而非业务语义。
  • 复合分区:先按一种策略分区,再在分区内按另一种策略子分区。
四种分区类型:数据落点与适用场景 范围分区 RANGE 2024-01 ~ 2024-03 2024-04 ~ 2024-06 2024-07 ~ 2024-09 连续区间 · 时间/ID 段 列表分区 LIST region = '华东' region = '华南' region = '华北' 离散枚举 · 地区/状态 哈希分区 HASH hash(user_id) % 4 = 0 hash(user_id) % 4 = 1 hash(user_id) % 4 = 2/3 均匀打散 · 无业务语义 复合分区 RANGE(月) → LIST(地区) RANGE(月) → HASH(用户) 先粗后细 · 两级裁剪 多维度 · 大表治理 写入落点判断流程 解析分区键 匹配分区定义 计算哈希/区间 写入目标分区 选择原则:查询裁剪优先,维护与回滚成本其次,最后才是均匀分布 时间归档选 RANGE;地区/状态选 LIST;无业务维度且需打散选 HASH;多维度大表选复合分区

二、范围分区:最贴近时间与生命周期

范围分区按分区键的连续区间划分,典型如按月份、季度、年份或自增 ID 段。它的最大优势是与数据生命周期天然对齐:历史数据归档、冷热分离、按时间回滚都可以通过 DROP PARTITION 或 EXCHANGE PARTITION 快速完成,避免大范围 DELETE 带来的锁与日志压力。

CREATE TABLE orders (
  order_id   BIGINT,
  user_id    BIGINT,
  order_time DATETIME,
  amount     DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(order_time)) (
  PARTITION p2023 VALUES LESS THAN (2024),
  PARTITION p2024 VALUES LESS THAN (2025),
  PARTITION p2025 VALUES LESS THAN (2026),
  PARTITION pmax  VALUES LESS THAN MAXVALUE
);

适用场景:订单、日志、流水、监控指标等按时间增长的数据。查询中若经常带 order_time 范围条件,分区裁剪效果最好。需要注意的是,范围分区容易产生热点分区——最新分区写入最频繁,若单分区过大,仍需进一步拆分或使用复合分区。

三、列表分区:面向离散枚举与业务维度

列表分区按分区键的离散值集合划分,每个分区对应一组明确的值。它适合地区、渠道、状态、租户类型等枚举维度。与范围分区不同,列表分区不要求值连续,因此可以灵活地把“华东、华南”放入一个分区,把“华北、西南”放入另一个分区。

CREATE TABLE customers (
  customer_id BIGINT,
  region      VARCHAR(20),
  level       VARCHAR(10)
)
PARTITION BY LIST (region) (
  PARTITION p_east  VALUES IN ('华东','华南'),
  PARTITION p_north VALUES IN ('华北','东北'),
  PARTITION p_west  VALUES IN ('西南','西北'),
  PARTITION p_other VALUES IN (DEFAULT)
);

适用场景:按地区做数据隔离、按状态做冷热分层、按租户做资源划分。列表分区的风险在于值域变化:新增地区或状态时,必须及时新增分区,否则会落入 DEFAULT 分区,导致数据倾斜甚至写入失败。因此,列表分区需要配合值域管理流程。

四、哈希分区:追求均匀分布与并发打散

哈希分区对分区键计算哈希值,再按分区数量取模,把数据尽量均匀地分散到各分区。它不保留业务语义,但能有效避免热点,提升并发写入与并行扫描能力。常见于用户表、设备表、流水表等没有明显时间或地区维度的场景。

CREATE TABLE user_events (
  event_id BIGINT,
  user_id  BIGINT,
  event_ts DATETIME
)
PARTITION BY HASH (user_id)
PARTITIONS 8;

适用场景:需要均匀打散、避免单分区过大、提升并行度。哈希分区的代价是范围查询裁剪弱:按 user_id 等值查询可以裁剪到单个分区,但按时间范围查询往往需要扫描所有分区。此外,分区数量变更时通常需要重新分布数据,扩容成本较高。

五、复合分区:先粗后细,兼顾多维治理

复合分区是在一种分区策略之上再嵌套另一种策略,例如先按时间做 RANGE 分区,再按地区做 LIST 子分区,或先按时间 RANGE,再按 user_id HASH。它适合数据量大、查询维度多、维护要求高的大表。

CREATE TABLE sales (
  sale_id   BIGINT,
  sale_date DATE,
  region    VARCHAR(20),
  amount    DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(sale_date))
SUBPARTITION BY HASH (sale_id) SUBPARTITIONS 4 (
  PARTITION p2024 VALUES LESS THAN (2025),
  PARTITION p2025 VALUES LESS THAN (2026)
);

复合分区的优势是两级裁剪:时间条件先裁掉历史分区,哈希或列表条件再裁掉子分区。它也能把“归档”和“打散”两个目标同时满足。但分区数量会成倍增加,元数据管理、DDL 耗时和优化器选择都会更复杂,必须控制层级与数量。

六、对比清单与选型建议

分区类型 切分依据 裁剪能力 维护与回滚 典型场景
范围分区 连续区间 时间/ID 范围裁剪强 DROP/EXCHANGE 快 订单、日志、流水
列表分区 离散枚举值 等值裁剪强 按业务维度归档 地区、状态、租户
哈希分区 哈希取模 等值裁剪强,范围弱 扩容需重分布 用户、设备、事件
复合分区 两级组合 多级裁剪 灵活但复杂 多维度大表
选型口诀:先看查询条件,再看维护动作,最后看分布均匀度。时间维度优先 RANGE;枚举维度优先 LIST;无业务维度且要打散用 HASH;单维度不够用时再上复合分区。

七、常见误区与复盘

  • 误区一:分区越多越好。分区数量过多会带来元数据膨胀、DDL 变慢、优化器裁剪开销上升,通常单表分区数控制在几十到几百级别更稳妥。
  • 误区二:哈希分区能解决所有热点。哈希只能打散分区级热点,若单分区内部仍有热点行或热点索引,仍需配合索引与缓存优化。
  • 误区三:列表分区不需要 DEFAULT。没有 DEFAULT 时,新增枚举值会导致插入失败;有 DEFAULT 又可能悄悄堆积数据,必须监控 DEFAULT 分区大小。
  • 误区四:复合分区一定优于单层分区。复合分区增加复杂度,若查询只命中一个维度,单层分区往往更简单高效。
回滚视角提醒:范围分区最适合按时间快速回滚;列表分区适合按业务维度回滚;哈希分区回滚粒度不直观,通常需要借助业务字段或额外映射表;复合分区回滚能力强,但必须提前规划好分区命名与归档路径,否则回滚时容易误删或漏删。

总结来说,分区类型没有绝对优劣,只有与业务查询、数据生命周期和维护策略是否匹配。范围分区解决“时间轴”问题,列表分区解决“枚举维度”问题,哈希分区解决“均匀打散”问题,复合分区解决“多维度治理”问题。理解它们的落点规则与裁剪边界,才能在性能优化与回滚之间取得平衡。