当需要在PolarDB PostgreSQL版中长期保留大量明细数据并执行扫描、聚合和分析查询时,可以使用云原生DuckDB列存表。本文介绍列存表的存储方式、支持范围和适用场景,帮助判断是否应使用列存表而非行存表或列存索引。
概念
云原生DuckDB列存表是PolarDB将 DuckDB 分析引擎深度集成到数据库内核后提供的列式存储能力。列存表使用 CREATE TABLE ... USING duckdb 创建,表的数据只保存在 DuckDB 列式数据文件中,由 DuckDB 负责列存表的扫描、过滤、聚合、关联,以及执行 UPDATE 和 DELETE 语句。
DuckDB 既是分析执行引擎,也是列存表的原生存储引擎。列存表本身保存主数据,不依赖 PostgreSQL 行存主表,也不是行存表的一份列存副本。DuckDB 的列式存储、数据压缩和向量化执行适合处理大量数据的分析查询。
这种存储和执行方式适合批量装载、大范围扫描及分析型查询。具体存储与查询收益取决于数据类型、数据分布和查询方式。依赖索引、物理行标识或行锁的事务处理负载仍应使用行存表。
与列存索引的区别
对比项 | 列存表 | 列存索引(IMCI) |
主数据 | DuckDB 列式数据文件 | PostgreSQL 行存表 |
创建方式 |
|
|
PostgreSQL 索引 | 不支持 | 行存表可继续使用 B-tree 等索引 |
主键、唯一约束和外键 | 不支持 | 由行存表和 PostgreSQL 索引实现 |
行锁和点查 | 不支持或不适合 | 可通过行存表执行 |
写入方式 | 直接写入列式数据文件 | 先写行存表,再同步列式副本 |
业务需要主键、唯一约束、外键、行级锁或高频点更新时,应使用行存表。需要同时进行事务处理和分析时,可以在行存表上创建列存索引。
适用场景
历史明细在线留存
订单流水、操作日志和监控事件不断累积,旧数据虽然很少修改,却仍可能用于审计、趋势分析或临时查询。将这类明细按批次装入列存表后,可以在同一PolarDB集群中继续使用 SQL 查询,无需为了分析而先将数据回迁到行存表。列式存储与压缩有助于控制空间占用,但实际节省量应以业务数据测试为准。数据有明确生命周期时,还可以按列存叶子分区组织,便于分批装载和淘汰。
构建分析主题表
当上游数据需要定期汇总为销售、运营或设备等主题数据集时,可以使用 COPY、INSERT ... SELECT或CREATE TABLE AS SELECT批量装载列存表,在PolarDB内保留可反复查询的分析明细和中间结果。相比大量单行写入,这种批量处理方式更符合 DuckDB 面向分析负载的设计。数据可以由现有加工流程准备,后续分析直接查询已装载的列存表。
报表与多维分析
报表常需从大量记录中筛选少数列,再按日期、地区或业务类别做聚合、窗口计算或列存表之间的 JOIN。DuckDB 的列式存储和向量化执行适合这类扫描型查询,在同一份列存数据上反复生成周期报表或开展临时分析时,也无需维护额外的行存主表与列存副本。实际性能仍取决于查询形态和数据规模。
不适用场景
依赖主键、唯一约束、外键、排除约束或 PostgreSQL 索引的表。
使用行锁、物理行标识、游标逐行读取或高并发点更新的应用。
需要在一条查询中关联行存表和列存表的业务。
要求一个事务原子修改多张列存表,或使用
PREPARE TRANSACTION的业务。依赖 publication、逻辑解码或 CDC 捕获每次行变更的业务。
适用范围
您的PolarDB PostgreSQL版集群版本需为:
PostgreSQL 14:2.0.14.22.49.0及以上版本。
PostgreSQL 16:2.0.16.14.21.0及以上版本。
PostgreSQL 18:2.0.18.6.5.0及以上版本。
支持范围
列存表主要支持以下功能:
永久普通表,以及分区表的列存叶子分区。
SELECT的投影、过滤、聚合、窗口、CTE、UNION ALL以及列存表之间的JOIN。INSERT、INSERT ... SELECT、UPDATE、DELETE、COPY和CREATE TABLE AS SELECT。建表时的
NOT NULL、DEFAULT、CHECK、SMALLSERIAL、SERIAL、BIGSERIAL、IDENTITY和受支持的存储生成列。重命名、单项增删列、部分类型变更、
TRUNCATE和DROP TABLE。PostgreSQL 事务的提交和回滚,以及同一张表上的事务内写后读。
pg_dump和逻辑恢复。
下列功能不受支持:
临时列存表以及
UNLOGGED列存表。PRIMARY KEY、UNIQUE、EXCLUDE、FOREIGN KEY和任何 PostgreSQL 索引。SELECT ... FOR UPDATE/SHARE、TABLESAMPLE、后续查询中的ctid以及游标扫描。分区父表上的
UPDATE和DELETE、更新分区键,以及UPDATE/DELETE的RETURNING。MERGE、两阶段提交、列存写入后的SAVEPOINT和逻辑复制。对列存表点名执行
ANALYZE,以及VACUUM、VACUUM ANALYZE、CLUSTER、VACUUM FULL和SET TABLESPACE。
创建语法
CREATE TABLE table_name (
column_name data_type [ column_constraint [...] ]
[, ...]
) USING duckdb;参数说明
参数 | 说明 |
| 列存表名称。 |
| 列名称。 |
| 列的数据类型。支持范围参见支持的数据类型。 |
| 列约束。建表时支持 |
| 指定创建云原生DuckDB列存表,创建列存表时必须显式书写。默认配置下, |
示例
以下示例创建一张保存销售明细的列存表,并通过 DuckDB 执行聚合查询:
创建一个DuckDB列存表:
CREATE TABLE columnar_sales ( sale_id serial, region_id integer NOT NULL, amount numeric(18, 2) DEFAULT 0 CHECK (amount >= 0), occurred_at timestamptz NOT NULL ) USING duckdb;插入测试数据:
INSERT INTO columnar_sales (region_id, amount, occurred_at) VALUES (10, 100.50, '2026-08-26 08:00:00+00'), (20, 200.00, '2026-08-26 09:00:00+00');进行查询:
SELECT region_id, count(*) AS order_count, sum(amount) AS total_amount FROM columnar_sales GROUP BY region_id ORDER BY region_id;