AO表和AOCO表的适用场景和选型

AO表和AOCO表的适用场景和选型

前言

PostgreSQL(Greenplum / GPDB) 体系里,AO(Append-Only Row) 和 AOCO(Append-Only Column) 是两种典型的**Append-Only **存储格式,主要用于 数据仓库 / OLAP 场景,区别核心在:

👉 AO = 行存追加表
👉 AOCO = 列存追加表

它们都不是 PostgreSQL 原生 Heap 表,而是 Greenplum 的高性能分析型存储。
下面从 原理、适用场景、性能对比、选型建议 给你系统讲清。

一、存储结构本质区别

类型 存储方式 数据组织
Heap(普通表) 行存 + 可更新 MVCC
AO 行存 + 追加写 不支持 UPDATE 原地
AOCO 列存 + 追加写 每列独立存储

AO(Append Only Row)

一行完整写在一起
[ row1 ]
[ row2 ]
[ row3 ]

AOCO(Append Only Column)

col1: v1 v2 v3 v4
col2: v1 v2 v3 v4
col3: v1 v2 v3 v4

适用场景详解

1. Heap表(PostgreSQL继承的行存)

  • 核心定位:OLTP友好型、维度表、小表。
  • 数据量:百万级以下,或单表<10GB。官方建议小表(<100万条)使用Heap。
  • 操作特征:频繁UPDATE/DELETE,大量点查询(带索引),并发小事务。
  • 典型对象:数据仓库中的维度表(用户表、产品表)、配置表、码表。
  • 为什么用它:MVCC机制成熟,行级锁开销可控,VACUUM清理速度比AO表快。

2. AORO表(Append-Optimized Row-Oriented)

  • 核心定位:大表的明细存储,写入密集且修改极少。
  • 数据量:千万级~亿级以上。
  • 操作特征:批量INSERT(ETL)、几乎无UPDATE、查询时需要读取大部分列(如SELECT * 明细查询)。
  • 典型对象:日志原始表、流水表、审计表。
  • 为什么用它:相比Heap,存储更紧凑、无空洞;相比AOCO,不需要列存重组开销。
  • 重要限制:不支持列级压缩,压缩算法仅zlib(开源版),ADD COLUMN会重写表(耗时极长)。

3. AOCO表(Append-Optimized Column-Oriented)

  • 核心定位:数仓核心事实表,OLAP分析场景的王者。
  • 数据量:TB级,宽表(几十~几百列)。
  • 操作特征:查询只取少数列(聚合、过滤),极少点查询;写入以批量追加为主。
  • 典型对象:交易事实表、点击流分析表、用户行为宽表。
  • 为什么用它:列级压缩(ZSTD可省75%空间)、只读所需列大幅降低I/O、支持向量化执行加速。
  • 特殊优势:DDL灵活,ADD COLUMN(DEFAULT NULL)不重写表,瞬间完成。

表性能全面对比

以下对比基于相同硬件环境、海量数据(亿级)的典型行为:

维度 Heap表 AORO表 AOCO表 关键结论
查询性能 差(扫描大表时I/O巨大) 中等(需读整行) 极优(仅读投影列) AOCO分析快,可快数倍至数十倍(取决列选择率)
压缩比 无(或页级压缩弱) 中等(整表zlib) 极高(ZSTD/LZ4/RLE) AOCO压缩率比AORO高60%~75%
写入速度 慢(索引维护、WAL) 极快(仅追加) 快(列存组装有开销) AORO批量导入最快,AOCO次之,Heap最慢
UPDATE/DELETE 支持好(适合单行) 极差(标记删除,VACUUM极慢) 极差(同左) 大表频繁更新禁止用AO
点查询(带索引) 最优 差(变长块寻址慢) 差(列重组开销大) 点查询必须用Heap
DDL灵活性 ADD COLUMN慢(需重写) ADD COLUMN 极慢(必重写) 最优(不重写) AOCO修改Schema几乎零成本
内存消耗 低(共享缓冲池) 低(不经过共享缓冲) 高(每分区每列有buffer) AOCO blocksize不可过大,否则内存爆炸
维护成本(VACUUM) 慢(需重构bitmap) 慢(同左) 有大量更新的AO表维护成本远高于Heap
逻辑备份 不支持增量 支持增量 支持增量 大表用AO便于备份策略

二、适用业务场景(最重要)

⭐ AO(行存)适合

1.宽表 + 经常查询整行

典型:

  • 明细表全量导出
  • 日志
  • 订单明细
  • 用户行为记录

查询:
👉 需要整行数据
👉 行存读取更快

select * from fact_order where id=?

2.中等列数(<100列)

列太多 AOCO更合适。

3.写入为主 + 查询不挑列

AO写入效率高,简单。

4.需要较频繁 UPDATE / DELETE(但仍不推荐)

AO支持但成本比Heap高。

⭐ AOCO(列存)适合(数据仓库王者)

1.超大表(TB / PB级)

列存压缩极高。

2.宽表(100+列)

典型:

用户画像
标签表
指标宽表
风控特征表

3️.查询只访问少量列 ⭐⭐⭐

OLAP经典:

select sum(amount)
from fact_order
where date between ...

只扫 2列:
date

amount

👉 行存必须读整行
👉 列存只读相关列

4.聚合分析极多

count
sum
avg
group by

列存CPU缓存友好。

5.高压缩需求

  • AOCO支持:
  • RLE
  • ZLIB
  • ZSTD

压缩率常见:

| 数据类型  | 压缩率   |
| ----- | ----- |
| 数值    | 5~20倍 |
| 低基数字段 | 50倍+  |
| 枚举    | 100倍  |

三、性能对比(核心结论)

假设:

表 100列
查询2列

1.扫描性能

查询类型 AO AOCO
select * ⭐⭐⭐⭐⭐ ⭐⭐⭐
读少量列 ⭐⭐ ⭐⭐⭐⭐⭐
聚合 ⭐⭐⭐ ⭐⭐⭐⭐⭐
宽表扫描 ⭐⭐ ⭐⭐⭐⭐⭐

结论:

  • 👉 全列读取:AO快
  • 👉 部分列:AOCO碾压

2️.存储空间

表类型 空间
Heap 100%
AO 60~80%
AOCO 10~30%

3.写入性能

操作 AO AOCO
批量INSERT ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
单行INSERT ⭐⭐⭐ ⭐⭐
UPDATE ⭐⭐
DELETE ⭐⭐

列存写入成本更高。

4.更新性能(关键)

Append Only 本质:

  • 👉 UPDATE = delete + insert
    但 AOCO更重:
  • 需要重写多列文件
  • block级
    结论:
    | 更新频率 | 推荐 |
    | ---- | ---- |
    | 高 | Heap |
    | 中 | AO |
    | 低 | AOCO |

5.CPU效率

AOCO更高:
原因:

  • 向量化
  • cache友好
  • 列压缩减少IO
    OLAP性能常见:
  • 👉 AOCO 比 AO 快 3~20倍

四、真实数据仓库选型经验(非常重要)

行业经验:

表类型 推荐存储
事实表(超大) AOCO
宽表 AOCO
标签表 AOCO
报表聚合结果 AOCO
日志 AO
明细导出表 AO
临时ETL表 AO
高频更新表 Heap

五、典型性能对比案例(真实)

数据:

10亿行
120列
查询3列
表类型 查询时间
Heap 120s
AO 95s
AOCO 6s

六、压缩能力对比

类型 压缩 可选
AO 行压缩 yes
AOCO 列压缩 非常强

AOCO支持:

ENCODING (compresstype=zstd)
ENCODING (compresstype=rle)
ENCODING (compresstype=zlib)

七、Greenplum官方推荐(核心)

Greenplum设计理念:

  • 👉 数据仓库默认用 AOCO

只有以下情况不用:

  • 高频更新
  • 经常 select *
  • 小表

八、创建语法示例

AO

CREATE TABLE t1(...)
WITH (appendonly=true, orientation=row);

AOCO

CREATE TABLE t2(...)
WITH (appendonly=true, orientation=column);

带压缩:

WITH (
  appendonly=true,
  orientation=column,
  compresstype=zstd,
  compresslevel=5
);

九、终极选型决策图(实战)

问自己4个问题:
Q1 数据量大吗?
是 → AOCO

Q2 查询只用部分列吗?
是 → AOCO

Q3 表是否宽?
50列 → AOCO

Q4 是否频繁更新?
是 → Heap / AO

十、一句话总结(架构级)

👉 AO = OLAP行存
👉 AOCO = OLAP列存(主流)
👉 AOCO = 数据仓库默认选择
👉 AO = 过渡方案
👉 Heap = 事务系统

建议优先:

大事实表 → AOCO + ZSTD
宽表 → AOCO + RLE
ETL中间表 → AO
高并发更新 → Heap

十一、查看数据库是以增删改查那种业务场景为主

在 Greenplum 里,系统不会直接告诉你“这个表是查询为主还是增删改为主”,
但可以通过 系统统计信息 + 访问模式分析 很准确判断。

核心思路:

  • 👉 看 读写操作比例
  • 👉 看 扫描方式
  • 👉 看 更新膨胀情况

下面给你 DBA 实战级判断方法。

1.查看表读写次数(最关键指标)

SELECT
    schemaname,
    relname AS table_name,
    seq_scan,      -- 全表扫描次数
    idx_scan,      -- 索引扫描次数
    n_tup_ins,     -- 插入行数
    n_tup_upd,     -- 更新行数
    n_tup_del,     -- 删除行数,
    n_live_tup,    -- 当前活跃行
    n_dead_tup     -- 死行(更新删除产生)
FROM pg_stat_user_tables
ORDER BY (n_tup_ins + n_tup_upd + n_tup_del) DESC;

2.企业级自动判断脚本(推荐)

SELECT
    schemaname,
    relname,
    seq_scan + idx_scan AS reads,
    n_tup_ins + n_tup_upd + n_tup_del AS writes,
    CASE
        WHEN (seq_scan + idx_scan) > 10*(n_tup_ins + n_tup_upd + n_tup_del)
            THEN '查询为主'
        WHEN (n_tup_ins + n_tup_upd + n_tup_del) > (seq_scan + idx_scan)
            THEN '写入为主'
        ELSE '混合'
    END AS workload_type
FROM pg_stat_user_tables
ORDER BY reads DESC;

同时查询表的大小
SELECT
    schemaname,
    relname,
    seq_scan + idx_scan AS reads,
    n_tup_ins + n_tup_upd + n_tup_del AS writes,
    CASE
        WHEN (seq_scan + idx_scan) > 10 * (n_tup_ins + n_tup_upd + n_tup_del)
            THEN '查询为主'
        WHEN (n_tup_ins + n_tup_upd + n_tup_del) > (seq_scan + idx_scan)
            THEN '写入为主'
        ELSE '混合'
    END AS workload_type,
    pg_size_pretty(pg_total_relation_size(relid)) AS table_size,
    pg_total_relation_size(relid) / (1024 * 1024 * 1024) AS table_size_gb  -- 转换成 GB
FROM pg_stat_user_tables
ORDER BY reads DESC;

直接给你存储选型决策

表类型 存储建议
查询为主 AOCO
写入为主 Heap
批量写入 AO
更新频繁 Heap
宽表分析 AOCO
posted @ 2026-03-19 14:23  数据库小白(专注)  阅读(2)  评论(0)    收藏  举报