DWS 列存表分区创建原理详解

DWS 列存表分区创建原理详解

在华为云 DWS 中,列存表的分区机制是影响查询性能和存储效率的核心设计之一。理解其底层原理,才能避开生产环境中的常见坑。

分区的本质:物理文件隔离

DWS 列存表以 CU(Compression Unit,压缩单元) 为最小存储单位,每个 CU 默认包含 60000 行数据,压缩后落盘为独立文件。分区在物理层面就是将这些 CU 文件按分区键的范围归组到不同目录下,每个分区拥有独立的元数据和文件空间。

查询时,优化器根据 WHERE 条件中的分区键值,直接跳过不满足条件的分区目录,这一机制称为分区裁剪(Partition Pruning)。被裁剪掉的分区不参与扫描,I/O 大幅减少,这是分区提升查询性能的根本原因。

列存分区与行存分区的关键差异

行存表支持 INTERVAL 自动分区,数据写入时若超出现有分区范围会自动创建新分区。列存表不支持这一特性,所有分区必须提前手动创建。

sql 复制代码
-- 行存表:支持 INTERVAL 自动分区
CREATE TABLE orders_row (
    order_id    BIGINT,
    created_at  TIMESTAMP
)
WITH (ORIENTATION = ROW)
DISTRIBUTE BY HASH(order_id)
PARTITION BY RANGE (created_at)
INTERVAL ('1 day')                        -- 自动按天建分区
(
    PARTITION p_init VALUES LESS THAN (TIMESTAMP '2025-01-01 00:00:00')
);

-- 列存表:不支持 INTERVAL,必须手动预建
CREATE TABLE orders_col (
    order_id    BIGINT,
    created_at  TIMESTAMP
)
WITH (ORIENTATION = COLUMN)
DISTRIBUTE BY HASH(order_id)
PARTITION BY RANGE (created_at)
(
    PARTITION p_2025_01 VALUES LESS THAN (TIMESTAMP '2025-02-01 00:00:00'),
    PARTITION p_2025_02 VALUES LESS THAN (TIMESTAMP '2025-03-01 00:00:00'),
    PARTITION p_2025_03 VALUES LESS THAN (TIMESTAMP '2025-04-01 00:00:00'),
    PARTITION p_future  VALUES LESS THAN (MAXVALUE)   -- 兜底分区,防止写入报错
);

MAXVALUE 兜底分区是生产环境必备,一旦数据超出已有分区范围,数据会落入兜底分区而不是直接报错。

CU 与分区粒度的关系

分区粒度过细会导致 CU 无法填满 60000 行就强制落盘,产生大量小 CU 碎片,压缩率下降,查询需要打开更多文件,性能反而变差。

sql 复制代码
-- 不推荐:按小时分区,一年产生 8760 个分区,CU 碎片严重
PARTITION BY RANGE (feature_hour)
(
    PARTITION p_2025_05_01_00 VALUES LESS THAN (TIMESTAMP '2025-05-01 01:00:00'),
    PARTITION p_2025_05_01_01 VALUES LESS THAN (TIMESTAMP '2025-05-01 02:00:00'),
    ...  -- 分区数量爆炸,元数据开销极大
);

-- 推荐:按天分区,查询按小时过滤同样能分区裁剪
PARTITION BY RANGE (feature_hour)
(
    PARTITION p_2025_05_01 VALUES LESS THAN (TIMESTAMP '2025-05-02 00:00:00'),
    PARTITION p_2025_05_02 VALUES LESS THAN (TIMESTAMP '2025-05-03 00:00:00'),
    PARTITION p_2025_05_03 VALUES LESS THAN (TIMESTAMP '2025-05-04 00:00:00'),
    PARTITION p_future     VALUES LESS THAN (MAXVALUE)
);

单个分区数据量建议在 1000 万行以上,按天或按月分区是最常见的合理选择。

定时预建分区

列存表需要配合定时任务提前建好未来分区,避免数据堆入兜底分区失去裁剪效果。

sql 复制代码
-- 创建预建分区的存储过程
CREATE OR REPLACE PROCEDURE rc_dws.add_daily_partitions(days_ahead INT DEFAULT 7)
LANGUAGE plpgsql AS $$
DECLARE
    v_date      TIMESTAMP;
    v_part_name VARCHAR(64);
BEGIN
    v_date := date_trunc('day', NOW());

    FOR i IN 0..days_ahead LOOP
        v_part_name := 'p_' || to_char(v_date + (i || ' days')::INTERVAL, 'YYYY_MM_DD');

        IF NOT EXISTS (
            SELECT 1 FROM pg_partition
            WHERE parentid    = 'rc_dws.orders_col'::regclass
              AND partitionname = v_part_name
        ) THEN
            EXECUTE format(
                'ALTER TABLE rc_dws.orders_col
                 ADD PARTITION %I VALUES LESS THAN (TIMESTAMP %L)',
                v_part_name,
                date_trunc('day', NOW()) + ((i + 1) || ' days')::INTERVAL
            );
            RAISE NOTICE '创建分区: %', v_part_name;
        END IF;
    END LOOP;
END;
$$;

-- 注册每天凌晨 1 点执行,提前预建未来 7 天分区
SELECT dbms_job.submit(
    what      => 'CALL rc_dws.add_daily_partitions(7);',
    next_date => TRUNC(SYSDATE + 1) + 1/24,
    interval  => 'TRUNC(SYSDATE + 1) + 1/24'
);

Min/Max 索引与分区裁剪的协同

每个 CU 头部记录该列的 Min/Max 值(Zone Map),查询引擎在分区内部还会做二次过滤,跳过不满足谓词的 CU 块。可以通过 EXPLAIN 验证分区裁剪是否生效:

sql 复制代码
-- 查看执行计划,确认是否触发分区裁剪
EXPLAIN SELECT * FROM rc_dws.orders_col
WHERE created_at >= '2025-05-01' AND created_at < '2025-05-02';

-- 执行计划中出现以下关键字说明裁剪生效
-- Partitions: p_2025_05_01   ← 只扫描目标分区
-- (Partition Eliminated: 29) ← 29 个分区被跳过

冷数据清理

分区表最大的运维价值之一是可以直接 DROP 历史分区,比 DELETE 快几个数量级:

sql 复制代码
-- 清理 3 个月前的历史数据,秒级完成
ALTER TABLE rc_dws.orders_col DROP PARTITION p_2025_01;

-- 或转移到冷存储表空间,降低存储成本
ALTER TABLE rc_dws.orders_col MOVE PARTITION p_2025_02 TABLESPACE cold_obs_tbs;

小结

DWS 列存分区 = 物理文件隔离 + 分区裁剪 + CU Zone Map 三层机制协同工作。分区粒度选对了性能事半功倍,选错了碎片和元数据开销反而拖慢整体表现。核心原则只有一条:分区粒度服务于查询模式,而不是数据写入频率

相关推荐
渐儿1 小时前
上下文工程 · 02 · 工具结果的反注入与信任边界
后端
得物技术1 小时前
基于 Harness + SDD + 多仓管理模式的 AI 全栈开发实践|得物技术
前端·人工智能·后端
掘金者阿豪1 小时前
服务器突然卡了却找不到原因?cAdvisor让每个容器都透明可见
后端
程序员三明治2 小时前
【AI】Prompt 工程入门:从五要素框架到 RAG 生产级 Prompt 模板与 Java 实战
java·人工智能·后端·大模型·llm·prompt·agent
雨辰AI2 小时前
SpringBoot3 + 人大金仓 V9 全栈日志实战:Logback + Loki + Filebeat 构建统一日志平台
java·数据库·后端·云原生·eureka·logback·政务
石小石Orz2 小时前
OpenAI官方:harness-engineering(工程技术:在智能体优先的世界中利用 Codex)
前端·后端
SamDeepThinking2 小时前
打造高效团队的四个关键动作
java·后端·团队管理
fliter2 小时前
WAF 机器学习推理从 1519μs 压到 275μs,Cloudflare 是怎么做到的
后端
Moment2 小时前
2026年,为什么NestJS + Monorepo越来越流行了 ❓❓❓
前端·后端·面试