pgColumnar 1.0-alpha4:用 Hilbert 曲线布局,让星型查询更会跳过无关数据

2026-09-18 28 预计阅读时间: 1 分钟
来源: postgr.es AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

pgColumnar 1.0-alpha4 于 2026 年 9 月 17 日发布,距离 1.0-alpha3 只有两周。这一版的主题很明确:改进列式数据的布局,并让查询更有效地跳过不相关的数据组。对于在 PostgreSQL 中运行分析型查询的团队来说,重点不只是“数据按列存储”,而是“相关数据能否被放在更近的位置,以及无关数据能否尽早不读”。

为什么布局方式会影响列式查询

列式存储通常会把数据按列组织,并进一步划分为多个数据组。查询只需要少数列时,可以避免读取整行;如果谓词还能判断某个数据组不可能匹配,就可以直接跳过这个数据组。

这使得数据布局成为性能的一部分。假设事实表同时包含 customer_idproduct_idevent_dateamount,查询经常按照多个维度过滤。如果相关键值在物理布局上相互靠近,数据组的范围更集中,跳过判断就更容易生效。反过来,随机写入或不合适的排序可能让每个数据组都混入大量不同范围,最终不得不读取更多数据。

Hilbert 曲线与 Z-order 的差别

alpha4 支持使用 Hilbert curve 组织表布局。Z-order,也称 Morton order,会把多个维度的坐标交错编码成一条线;Hilbert curve 则通过连续曲线遍历多维空间。

直观地说,Hilbert 曲线更重视局部连续性:在多维空间中相邻的键,通常更有机会在一维存储顺序中保持接近。对于多列过滤条件,这可能形成更紧凑的数据组,从而提升谓词下推和数据跳过的收益。

这并不意味着 Hilbert 布局在所有负载中都必然更快。布局需要结合实际过滤列、数据分布、批量写入方式和查询模式评估。只有当查询经常在多个维度上筛选,并且数据组的跳过可以显著减少读取量时,布局优化才有明显价值。

星型连接中的事实表跳过

本版本还改进了星型模式下的连接处理:查询在连接维表和事实表时,可以跳过不匹配的事实表数据组。

典型场景是:

  • 事实表保存大量销售或事件记录;
  • 维表保存客户、产品、地区等相对较小的数据;
  • 查询先用维表条件筛选出一小部分键,再连接事实表;
  • 事实表中绝大多数数据组都不可能包含这些键。

在这种情况下,优化器或执行层如果能利用数据组的键范围、统计信息或布局特征,就可以避免扫描全部事实数据。需要注意的是,“支持跳过”不等于每条星型连接都会自动获得收益。维度过滤条件的选择性、事实表的数据分布、连接列的布局以及统计信息质量都会影响结果。

可以这样建立一个最小验证环境

下面的示例使用 PostgreSQL 和 pgColumnar 的典型用法创建一个小型事实表,并通过 EXPLAIN 观察查询计划。示例中的 USING columnar 是可直接改造的基础写法;Hilbert 布局的具体建表参数或管理命令应以所使用的 alpha4 构建版本文档为准,因为该功能仍处于 alpha 阶段。

运行前准备一个已经安装并允许加载 pgColumnar 的 PostgreSQL 实例:

CREATE EXTENSION IF NOT EXISTS columnar;

DROP TABLE IF EXISTS sales_fact;

CREATE TABLE sales_fact (
    event_date  date,
    customer_id bigint,
    product_id  bigint,
    region      text,
    amount      numeric(12, 2)
) USING columnar;

INSERT INTO sales_fact (event_date, customer_id, product_id, region, amount)
SELECT
    date '2026-01-01' + (g % 90),
    (g % 10000) + 1,
    (g % 1000) + 1,
    CASE g % 4
        WHEN 0 THEN 'east'
        WHEN 1 THEN 'west'
        WHEN 2 THEN 'north'
        ELSE 'south'
    END,
    round((random() * 500)::numeric, 2)
FROM generate_series(1, 1000000) AS s(g);

ANALYZE sales_fact;

EXPLAIN (ANALYZE, BUFFERS)
SELECT product_id, sum(amount) AS revenue
FROM sales_fact
WHERE event_date >= date '2026-02-01'
  AND event_date <  date '2026-03-01'
  AND region = 'east'
GROUP BY product_id
ORDER BY revenue DESC
LIMIT 20;

这个实验的重点不是单次执行时间,而是建立基线:记录计划、实际读取的缓冲区和运行耗时,然后再用 alpha4 支持的 Hilbert 布局方式重建一份表,使用同样的数据和查询进行对比。建议至少比较以下指标:

  1. 扫描的数据组数量或等价的跳过信息;
  2. Buffers 中的读取量;
  3. 冷缓存和热缓存下的执行时间;
  4. 不同选择性过滤条件下的表现;
  5. 批量追加数据后性能是否仍然稳定。

如果要验证星型连接,可以补充一个小维表,并让维表条件只选出少量客户:

DROP TABLE IF EXISTS customer_dim;

CREATE TABLE customer_dim (
    customer_id bigint PRIMARY KEY,
    segment     text
);

INSERT INTO customer_dim
SELECT
    g,
    CASE WHEN g <= 100 THEN 'target' ELSE 'other' END
FROM generate_series(1, 10000) AS s(g);

ANALYZE customer_dim;

EXPLAIN (ANALYZE, BUFFERS)
SELECT sum(f.amount)
FROM sales_fact AS f
JOIN customer_dim AS d
  ON d.customer_id = f.customer_id
WHERE d.segment = 'target';

如果该查询仍然读取了大量事实表数据,不要立刻判断功能无效。先确认事实表是否按照合适的维度组织、数据是否以足够大的批次写入、统计信息是否最新,并检查 alpha4 版本是否要求额外的布局配置。

采用前要留意的边界

pgColumnar 1.0-alpha4 仍是 alpha 版本,适合在隔离环境中验证,而不应仅凭一个微型测试就迁移核心生产负载。布局通常是写入和重组阶段的决策:更好的查询跳过能力可能伴随重写成本、批量导入约束或维护复杂度。

可以用下面的清单推进评估:

  • 先挑选真正以分析读取为主、更新模式相对简单的事实表;
  • 用生产级数据分布,而不是均匀随机数据做基准;
  • 分别测试单列过滤、多列过滤和星型连接;
  • 对比 Hilbert 布局与现有布局,而不是只测一个绝对数字;
  • 记录装载时间、存储体积、查询延迟和重建成本;
  • 为 alpha 功能设置回滚路径,并固定测试版本。

alpha4 的价值在于把列式存储的优化从“少读几列”推进到“少读几个数据组”。如果你的 PostgreSQL 分析工作负载具有明显的多维过滤和星型连接特征,Hilbert 布局与事实表跳过值得进入基准测试清单,但最终选择仍应由真实数据和真实查询决定。


相关推荐