一、分区表基础:什么是分区表、优势与适用场景、分区键选择原则

1.1 分区表到底是什么?

先说说我对分区表的理解。说白了,分区表就是把一张大表,按某种规则拆成多个物理小表。但对外,它还是一张表。你查询的时候,SQL 还是写 SELECT * FROM orders,数据库自动帮你决定去哪个分区拿数据。

我记得刚入行时,有个同事把一张 5TB 的日志表扔在单个表空间里,查询慢得离谱。后来改成按月分区,同样的查询,速度提升了 20 倍。嗯,这就是分区表的魅力。

分区表的底层实现,其实就是一个「逻辑表 + 多个物理分区」的组合。每个分区有自己的数据文件、索引文件,甚至可以放在不同的磁盘上。

核心概念:分区表 = 逻辑上的单表 + 物理上的多段存储。对应用层透明,对 DBA 可控。

1.2 分区表的优势

我总结了四个核心优势,都是我在项目中实打实验证过的:

  • 查询性能提升——分区裁剪(Partition Pruning)机制。你查 1 月份的数据,数据库只扫 1 月那个分区,其他分区碰都不碰。我见过一个案例,全表扫描要 40 秒,分区裁剪后降到 0.8 秒。
  • 管理更灵活——你可以单独备份、恢复、重建某个分区,不用动整张表。我曾经在凌晨 2 点只重建了一个损坏的分区,业务完全无感知。
  • 数据生命周期管理——旧数据直接 DROP 分区,比 DELETE 快几个数量级。DELETE 1 亿行可能要跑几小时,DROP 分区只要几秒。
  • 并行处理能力——数据库可以同时扫描多个分区,充分利用多核 CPU。
对比维度 普通表 分区表
查询大范围数据 全表扫描,慢 分区裁剪,快
删除旧数据 DELETE 慢,产生大量日志 DROP 分区,秒级完成
备份恢复 只能整表操作 可分区级操作
索引维护 全局索引,重建成本高 局部索引,重建快

1.3 适用场景

不是所有表都适合分区。我见过有人把只有几千行的配置表也分了区,纯粹是给自己找麻烦。分区表最适合以下场景:

  • 大表——单表数据量超过 100GB 或行数过亿,查询和维护开始吃力时。
  • 有明显的时间维度——比如订单表、日志表、交易流水表。按月或按天分区,天然合适。
  • 有明确的数据生命周期——比如只保留最近 6 个月的数据,每个月归档一次旧数据。
  • 需要并行扫描——报表系统、数据仓库场景,经常要扫全量数据做聚合。

我的经验:如果你不确定要不要分区,先问自己三个问题:这张表超过 5000 万行了吗?查询条件里有没有固定的过滤字段?数据有明确的保留期限吗?三个都答「是」,那就大胆分区。

1.4 分区键的选择原则

分区键选错了,分区表还不如普通表。我曾经接手过一个项目,前人用 status 字段做分区键,结果 90% 的数据都在「已完成」分区里,其他分区几乎空的。分区裁剪完全失效,查询反而更慢。

选分区键,我建议遵循这几个原则:

  1. 高选择性——分区键的值分布要均匀。比如按月份分区,每个月的数据量差不多。别用性别、状态这种只有两三个值的字段。
  2. 查询条件中频繁出现——分区键要能出现在 WHERE 子句里,否则分区裁剪用不上。你想想看,如果按 order_date 分区,但查询条件里从来不查日期,那分区就白做了。
  3. 数据量可预测——每个分区的数据量要相对稳定。比如按天分区,每天 100 万行,这样每个分区的性能表现一致。
  4. 尽量用时间字段——我个人的习惯是,80% 的分区表都用时间字段做分区键。时间天然有序,数据生命周期管理也方便。

避坑指南:我曾经见过有人用 UUID 做分区键,结果每次插入都跨分区,性能比普通表还差。分区键不要用随机性太强的字段,否则写入会变成「全分区扫描」。

1.5 分区表核心结构图

下面这张图,是我自己画的分区表核心结构。你可以看到逻辑表如何映射到物理分区,以及查询时分区裁剪的路径。

分区表核心结构图 分区表核心结构图 逻辑表 (orders) 分区路由 (Partition Map) 分区 p202401 2024年1月数据 分区 p202402 2024年2月数据 分区 p202403 2024年3月数据 查询: SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31' 分区裁剪:只扫描 p202401 分区,其他分区跳过 全表扫描 3 个分区 → 裁剪后只扫 1 个分区,性能提升 3 倍 逻辑表对外透明,应用无感知 物理分区可独立管理、备份、恢复 分区键选择不当 → 分区裁剪失效 查询性能反而下降,写入变慢

1.6 分区键选择决策表

最后,我整理了一张分区键选择决策表。你在设计分区表时,可以对照着选:

业务场景 推荐分区键 分区类型 注意事项
订单/交易流水 order_date / created_at RANGE 分区(按月) 避免跨月查询,否则会扫多个分区
日志数据 log_time RANGE 分区(按天) 每天数据量要均匀,避免某天暴增
用户数据 user_id 哈希 HASH 分区 分区数取 2 的幂,数据分布更均匀
地区数据 region_code LIST 分区 每个分区数据量不能差太多
物联网传感器 device_id 哈希 + 时间 复合分区 先哈希再范围,兼顾写入和查询

我的建议:刚开始做分区表,先从 RANGE 分区入手,按时间分。这是最稳妥、最容易理解的方式。等你把分区裁剪、分区交换、分区合并这些操作都玩熟了,再考虑 HASH 或 LIST 分区。