4、分区表创建与管理:从建表到日常运维

分区表这东西,光会建是不够的。你得知道怎么建、怎么改、怎么修。我做了这么多年数据库,见过太多人建完分区就扔那儿不管了,结果数据一多,性能反而更差。今天咱们就把创建、维护、交换这几个核心操作捋一遍。

4.1 创建分区表:语法其实不复杂

先看最基础的——CREATE TABLE ... PARTITION BY。Oracle、MySQL、PostgreSQL 语法略有差异,但核心逻辑一样:告诉数据库按哪个列、用什么规则切分数据。

我个人习惯用范围分区(RANGE),因为它最直观。比如按时间切:

CREATE TABLE orders (
    order_id     NUMBER,
    order_date   DATE,
    customer_id  NUMBER,
    amount       NUMBER
)
PARTITION BY RANGE (order_date) (
    PARTITION p_2023q1 VALUES LESS THAN (DATE '2023-04-01'),
    PARTITION p_2023q2 VALUES LESS THAN (DATE '2023-07-01'),
    PARTITION p_2023q3 VALUES LESS THAN (DATE '2023-10-01'),
    PARTITION p_2023q4 VALUES LESS THAN (DATE '2024-01-01'),
    PARTITION p_future  VALUES LESS THAN (MAXVALUE)
);

注意最后那个 MAXVALUE 分区。我在项目中遇到过,有人忘了加这个兜底分区,结果 2024 年的数据插不进去,线上直接报错。嗯,这里要注意——兜底分区不是可选项,是必选项。

我的建议: 兜底分区单独放一个表空间,方便后续拆分。别跟正常分区混在一起。

除了 RANGE,还有 LIST 和 HASH。LIST 适合按地区、状态等离散值切分:

PARTITION BY LIST (region) (
    PARTITION p_north VALUES ('北京','天津','河北'),
    PARTITION p_south VALUES ('广东','广西','海南'),
    PARTITION p_other VALUES (DEFAULT)
);

HASH 则适合均匀打散数据,比如按用户 ID 哈希:

PARTITION BY HASH (customer_id) PARTITIONS 8;

三种方式怎么选?我列个表给你参考:

分区类型 适用场景 优点 缺点
RANGE 时间、数值范围 易于管理历史数据,分区裁剪效果好 数据倾斜可能明显
LIST 离散值(地区、状态) 语义清晰,按业务维度切分 分区数有限,新增值需维护
HASH 均匀分布、无自然分区键 数据分布均匀,避免热点 分区裁剪效果差,不适合范围查询

4.2 添加与删除分区:日常运维基本功

分区表建好之后,最频繁的操作就是加分区和删分区。你想想看,时间分区表每个月都要加新分区,历史数据也要定期清理。

添加分区:

-- 在末尾添加新分区
ALTER TABLE orders ADD PARTITION
    PARTITION p_2024q1 VALUES LESS THAN (DATE '2024-04-01');

-- 在中间插入分区(需要先拆分)
ALTER TABLE orders SPLIT PARTITION p_future AT (DATE '2024-04-01')
    INTO (PARTITION p_2024q1, PARTITION p_future);

删除分区:

ALTER TABLE orders DROP PARTITION p_2023q1;

删除分区时,数据会一起被删掉。我曾经见过有人手抖删错了分区,还好有备份。所以我的习惯是——删除前先查一下分区数据量,确认无误再执行。

警告: DROP PARTITION 是 DDL 操作,会隐式提交事务。一旦执行,无法回滚!如果你需要保留数据,先做分区交换(后面会讲)。

4.3 合并与拆分分区:应对数据变化

业务变化了,分区策略也得跟着变。比如季度分区改成半年分区,或者某个分区数据太多需要拆细。

合并分区:

ALTER TABLE orders MERGE PARTITIONS p_2023q1, p_2023q2 INTO PARTITION p_2023h1;

合并后,两个分区的数据会归到新分区里。注意,合并后的分区边界取两个分区的最小值和最大值。

拆分分区:

ALTER TABLE orders SPLIT PARTITION p_2023h1 AT (DATE '2023-04-01')
    INTO (PARTITION p_2023q1, PARTITION p_2023q2);

拆分时,AT 指定的是分割点。分割点左边的数据进第一个分区,右边的进第二个。我在项目中遇到过一个问题——拆分时如果分割点跟已有数据边界冲突,会报错。所以拆分前最好先确认一下数据分布。

核心原则: 合并和拆分都会触发数据移动,大分区操作建议在维护窗口执行。别在业务高峰期搞这个。

4.4 分区交换:零停机数据迁移的利器

分区交换(Partition Exchange)是我最喜欢的功能。它可以在毫秒级别把一张普通表的数据“换”进分区,或者把分区数据“换”出来。

语法很简单:

-- 把普通表的数据换进分区
ALTER TABLE orders EXCHANGE PARTITION p_2023q1
    WITH TABLE orders_staging;

-- 把分区数据换出到普通表
ALTER TABLE orders EXCHANGE PARTITION p_2023q1
    WITH TABLE orders_archive;

交换的前提条件:

  • 普通表的结构必须与分区表完全一致(列名、数据类型、索引等)
  • 普通表的数据必须满足该分区的边界条件
  • 交换操作不涉及数据复制,只修改数据字典

我曾经用分区交换做过一个历史数据归档方案:每个月把上个月的分区数据换到归档表,然后删除原分区。整个过程对业务完全透明,用户根本感觉不到。

实用技巧: 分区交换前,先对普通表做一次 VALIDATE 检查,确保数据不越界。否则交换会失败,而且错误信息不太友好。

4.5 知识体系总览

下面这张图把分区表创建与管理的核心操作串起来了。你可以把它当作日常运维的速查地图:

分区表创建与管理核心操作 分区表 CREATE TABLE ... PARTITION BY RANGE 分区 LIST 分区 HASH 分区 日常维护操作 添加/删除分区 合并/拆分分区 分区交换 TRUNCATE 分区 核心原则:分区操作是 DDL,会隐式提交事务 大分区操作(合并/拆分/交换)建议在维护窗口执行

4.6 避坑指南:我踩过的几个坑

最后分享几个实战中容易翻车的地方:

  • 分区键不能更新:一旦表按某列分区,就不能直接 UPDATE 该列的值。想改?只能删了重插。所以分区键选好后别轻易改。
  • 全局索引会失效:对分区表做 DROP、TRUNCATE、SPLIT 等操作时,全局索引会变成 UNUSABLE。记得重建:ALTER INDEX idx_name REBUILD。
  • 分区数不是越多越好:我见过有人建了 1024 个分区,结果查询计划生成时间比执行时间还长。一般建议单表分区数不超过 100 个。
  • MAXVALUE 分区要定期拆分:兜底分区数据会越积越多,如果不拆分,它就成了一个“伪分区表”,性能反而更差。
一句话总结: 分区表的管理不是建完就完事了。添加、删除、合并、拆分、交换——这些操作你得练熟,才能在线上游刃有余。