1. 分区表基础概念

说实话,我刚接触分区表那会儿,也觉得这东西挺玄乎的。不就是把一张大表拆成几张小表吗?后来在项目里踩过坑,才真正理解了它的精髓。

今天咱们就来聊聊分区表最核心的几个概念。我会结合自己这些年摸爬滚打的经验,把这块讲透。

什么是表分区

表分区,说白了就是「分而治之」的思想。一张表数据量太大,查询慢、维护难,怎么办?把它按某种规则拆成多个物理片段,每个片段独立存储、独立管理。

但注意,从应用层看,它还是一张表。你写 SELECT * FROM orders,数据库会自动帮你定位到正确的分区。这就是透明性。

核心要点:分区是物理存储层面的拆分,逻辑层面仍然是完整的一张表。

我记得有一次,某电商平台的订单表到了 5 亿行,全表扫描一次要 40 多分钟。后来按月份做了范围分区,查询最近三个月的订单,秒级返回。这就是分区的威力。

分区键的选择

分区键选得好不好,直接决定了分区方案成败。我见过太多选错分区键导致性能反而下降的案例。

选分区键,我一般遵循这几个原则:

  • 查询频率高:分区键要能覆盖大部分查询的 WHERE 条件
  • 数据分布均匀:别让某个分区数据量特别大,其他分区空着
  • 不易变更:分区键一旦确定,修改起来非常麻烦
  • 有业务意义:比如时间、地域、用户 ID 这类天然有区分度的字段

我的经验:时间字段是最常用的分区键。为什么?因为大部分业务数据都有时间属性,而且查询通常也带时间范围。我做过的大项目,80% 以上都是用时间做分区键。

举个例子,订单表用 order_date 做分区键,查询「上个月的订单」就只需要扫描一个分区。如果用 order_id 做分区键,那查询条件里必须带上 order_id 范围才能走分区裁剪,否则就是全分区扫描。

分区类型详解

MySQL、PostgreSQL、Oracle 这些主流数据库,分区类型大同小异。我按最常见的四种来展开。

范围分区(RANGE)

这是最常用的一种。按连续的值范围来划分,典型的就是按时间。

CREATE TABLE orders (
    order_id INT,
    order_date DATE,
    amount DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

适用场景:时间序列数据、日志数据、历史归档数据。

我曾经帮一家金融公司做数据归档,他们的交易流水表按季度分区。每个季度结束后,直接把上个季度的分区设为只读,备份时只备份那个分区。效率提升了好几倍。

列表分区(LIST)

按离散的值列表来划分。比如按地区、按状态、按类型。

CREATE TABLE employees (
    emp_id INT,
    name VARCHAR(50),
    region VARCHAR(20)
)
PARTITION BY LIST (region) (
    PARTITION p_north VALUES IN ('北京', '天津', '河北'),
    PARTITION p_south VALUES IN ('广东', '广西', '海南'),
    PARTITION p_east VALUES IN ('上海', '江苏', '浙江'),
    PARTITION p_other VALUES IN ('其他')
);

适用场景:数据有明显的地域或类别属性,且查询经常按这些属性过滤。

注意:列表分区要确保所有可能的值都有对应的分区。我曾经遇到过线上报错,就是因为新插入的数据找不到匹配的分区。所以建议加一个 DEFAULT 分区兜底。

哈希分区(HASH)

按哈希函数的结果来分配数据。适合数据分布不均匀,但又没有天然分区键的场景。

CREATE TABLE user_sessions (
    session_id INT,
    user_id INT,
    login_time DATETIME
)
PARTITION BY HASH (user_id)
PARTITIONS 8;

适用场景:数据量大但查询条件不固定,或者想均匀分散 I/O 压力。

嗯,这里要注意:哈希分区的分区数最好是 2 的幂次方。为什么?因为哈希取模运算在 2 的幂次方下效率最高。这是底层实现决定的,咱们记住就好。

复合分区(COMPOSITE)

先按一种方式分区,再在每个分区内按另一种方式子分区。说白了就是分区套分区。

CREATE TABLE logs (
    log_id INT,
    log_date DATE,
    log_level VARCHAR(10),
    message TEXT
)
PARTITION BY RANGE (YEAR(log_date))
SUBPARTITION BY HASH (log_level)
SUBPARTITIONS 4 (
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025)
);

适用场景:数据量极大(百亿级别),单一分区维度不够用。比如先按年分区,再按日志级别哈希子分区。

我个人习惯是,能不用复合分区就不用。为什么?管理复杂度翻倍。除非数据量真的到了非用不可的地步,否则单层分区就够了。

知识体系总览

下面这张图,是我梳理的分区表核心知识结构。你看一眼,心里就有谱了。

分区表核心知识体系 表分区 分区键选择 • 查询频率高 • 数据分布均匀 • 不易变更 范围分区 RANGE • 按连续值范围划分 • 典型:时间序列 • 适用:日志、归档 列表分区 LIST • 按离散值列表划分 • 典型:地区、状态 • 注意:加 DEFAULT 兜底 哈希 / 复合分区 • HASH:均匀分散 I/O • COMPOSITE:分区套分区 • 适用:百亿级数据 核心思想:分而治之,逻辑统一,物理独立

避坑指南

最后,分享几个我踩过的坑,希望能帮你少走弯路。

我曾经犯过的错:

  • 分区数设得太多(比如 1024 个),结果每个分区文件都很小,反而增加了文件系统开销。建议分区数控制在 50 以内。
  • 用字符串字段做分区键,导致分区裁剪失效。分区键尽量用整数或日期类型。
  • 忘了给分区表加索引。分区表每个分区独立,索引也要在每个分区上建。全局索引和本地索引的区别,后面章节会细讲。

你想想看,分区表其实就是一个「拆」字。拆得好,性能翻倍;拆不好,维护成本暴增。选对分区键、选对分区类型,这两步走对了,后面就顺了。

好了,这一章就到这里。记住我今天讲的这几个核心概念,后面咱们聊备份还原的时候,你就知道为什么分区表备份能那么快了。

可可精品资料库