PostgreSQL表分区

Eave 2025.11.13

PostgreSQL支持基本的表分区功能。分区的意思是把逻辑上的一个大表分割成物理上的几块。分区可以提供若干好处:

  • 某些类型的查询性能可以得到极大提升。特别是表中访问率较高的行位于一个单独分区或少数几个分区上的情况下。分区可以减少索引体积从而可以将高使用率部分的索引存放在内存中。如果索引不能全部放在内存中,那么在索引上的读和写都会产生更多的磁盘访问。
  • 当查询或更新一个分区的大部分记录时,连续扫描那个分区而不是使用索引离散的访问整个表可以获得巨大的性能提升。
  • 如果需要大量加载或者删除的记录位于单独的分区上,那么可以通过直接读取或删除那个分区以获得巨大的性能提升,因为ALTER TABLE比操作大量的数据要快的多。它同时还可以避免由于大量DELETE导致的VACUUM超载。
  • 很少用的数据可以移动到便宜一些的慢速存储介质上。
  • 这种好处通常只有在表可能会变得非常大的情况下才有价值。到底多大的表会从分区中收益取决于具体的应用, 不过有个基本的拇指规则就是表的大小超过了数据库服务器的物理内存大小。

    目前,PostgreSQL支持通过表继承进行分区。每个分区必须做为单独一个父表的子表进行创建。父表自身通常是空的,它的存在只是为了代表整个数据集。你在试图实现分区之前,应该先熟悉继承。

    PostgreSQL可以实现下面形式的分区:

    范围分区:表被一个或者多个关键字段分区成"范围",这些范围在不同的分区里没有重叠。比如,我们可以为特定的商业对象根据数据范围分区,或者根据标识符范围分区。

    列表分区:表通过明确地列出每个分区里应该出现那些关键字值实现。

    要设置一个分区的表,做下面的步骤:

    创建"主表",所有分区都从它继承。

    这个表中没有数据,不要在这个表上定义任何检查约束,除非你希望约束同样也适用于所有分区。同样,在其上定义任何索引或者唯一约束也没有意义。

    创建几个"子表",每个都从主表上继承。通常,这些表不会增加任何字段。

    我们将把子表称作分区,尽管它们就是普通的PostgreSQL表。

    给分区表增加约束,定义每个分区允许的健值。

    典型的例子是:

    CHECK ( x = 1 )
    CHECK ( county IN ( 'Oxfordshire', 'Buckinghamshire', 'Warwickshire' ))
    CHECK ( outletID >= 100 AND outletID < 200 )

    确保这些约束能够保证在不同的分区里不会有重叠的键值。一个常见的错误是设置下面这样的范围:

    CHECK ( outletID BETWEEN 100 AND 200 )
    CHECK ( outletID BETWEEN 200 AND 300 )

    比如,假设我们为一个巨大的冰激凌公司构造数据库。该公司每天都测量最高温度,以及每个地区的冰激凌销售。概念上,我们需要一个这样的表:

    CREATE TABLE measurement (
        city_id         int not null,
        logdate         date not null,
        peaktemp        int,
        unitsales       int
    );

    然后我们为每个月创建一个分区

    CREATE TABLE measurement_200602 (
        CHECK ( logdate >= DATE '2006-02-01' AND logdate < DATE '2006-03-01' )
    ) INHERITS (measurement);