Vertica 列编码策略优化¶
作者:JiangChong | 撰写时间:2026年06月
适用场景框: 你发现集群存储增长快于预期、AUTO 编码占比过高(如 > 80%)、或想通过编码优化在不改硬件的前提下同时降低存储和 I/O 开销——但在 AUTO / RLE / BLOCKDICT_COMP / COMMONDELTA_COMP 等编码类型之间不知道怎么选。
关联文章:
- MPP 列存引擎的架构设计哲学 — 编码在列存五级演进中的位置与原理
- Vertica 性能调优 - 2 使用系统表排除 Vertica 查询性能故障 — 编码类型参考表与诊断 SQL
- Vertica 性能调优 - 3 重新设计 PROJECTION — 编码在投影设计中的角色
- Vertica 列数据类型与长度优化 — 数据类型定义如何限制编码选择
- Vertica 宽表(多列表)的存储与查询优化 — 宽表场景下的编码策略
- Vertica CPU 持续高负载诊断与优化 — 编码对 CPU 的影响
- 20230324某省级运营商集市库 BIZ_MART 表编码压缩优化报告 — 570 表编码优化的真实案例
理解全文脉络¶
本文从 Vertica 编码的底层原理出发,逐层解释 AUTO 编码做了什么选择、RLE/BLOCKDICT_COMP/COMMONDELTA_COMP 等编码各自适合什么数据特征、以及编码选择如何同时在压缩率和 CPU 开销两个维度上影响查询。如果你只想快速修复,直接跳到第 7 节:快速诊断 SQL 工具箱执行前三条 SQL,然后对照第 8 节:最佳实践清单逐条处理;如果你想深入理解原理再做决策,建议从第 1 节开始读。
第 1 节:原理理解 — 编码在 Vertica 中的角色¶
1.1 编码不是压缩——它们是两件不同的事¶
在 Vertica 的存储管线中,编码(Encoding)和压缩(Compression)是两个独立且叠加的层次。但它们的边界比字面意思更微妙——理解这二者的实际行为,是正确选择编码策略的前提。
| 层次 | 作用 | 举例 | 查询时是否需要解码 |
|---|---|---|---|
| 编码 | 对数据值的数学转换 | RLE 将 (HPQ, 2000万次) 存为一个三元组;Int_Delta 存储相邻值的差值 |
否——Vertica 可以直接在编码数据上做谓词计算和聚合 |
| 结构化压缩 | 保留数据数学结构的压缩 | block dictionary(块内字典)、int delta(差值编码)、int common delta(公共差值+字典) |
否——引擎可调整比较值/查字典来绕过解压 |
| 通用字节流压缩 | 对二进制数据的盲压缩 | lzo、zstd fast |
是——必须先解压还原为结构化数据 |
关键洞察:
column_storage表中标记为compressions的并非都需要解压。真正需要解压的只有 LZO / ZSTD 这类通用字节流压缩——它们不保留值的数学结构。而int delta、block dictionary、int common delta虽是compressions分类,实质是结构化压缩,Vertica 可以直接在它们上面运算(如 delta 压缩只需调整谓词比较值,字典压缩只需查字典)。论文依据:
- 这一设计可以追溯到 C-Store 原始论文(C-Store: A Column-oriented DBMS):「C-Store operators have the capability to operate on both compressed and uncompressed input」(§8.2),并将「operate on compressed representation」列为性能优势的四大核心原因之一(§9)。
- C-Store 7 Years(The Vertica Analytic Database - CStore 7 Years Later)确认 Vertica 延续了这一设计:「significant care has been taken... to ensure operators can operate directly on encoded data, which is especially important for scans, joins and certain low level aggregates」(§6.1)。
- SIPS 论文(SIPS - Materialization Strategies in the Vertica Analytic Database: Lessons Learned)给出了最具体的机制描述——RLE 列上的谓词 「can be applied directly on the encoded data, thus bypassing the overhead of decompression」,并通过 SIP 过滤器将 JOIN 谓词下推到 RLE 编码列上直接求值(§V-B)。
- verticaOptimizer 论文(The Vertica Query Optimizer: The Case for Specialized Query Optimizers)从优化器角度确认了 「delaying column decompression」 作为一个显式的运行时优化策略(§IV-G),并建立了压缩感知的代价模型(§IV-F1)。
在系统表中,这三层对应关系如下(来源:v26.1.0-2 实测):
| DDL 编码名 ( projection_columns.encoding_type) |
内部编码 ( column_storage.encodings) |
内部压缩 ( column_storage.compressions) |
需解压? |
|---|---|---|---|
AUTO(整数列) |
Uncompressed |
int delta |
❌ 结构化 |
AUTO(VARCHAR) |
String |
lzo |
✅ LZO |
RLE |
RLE |
lzo |
⚠️ RLE 可直接运算,但外层 LZO 需解压 |
DELTAVAL |
Int_Delta |
none |
❌ 无压缩层 |
BLOCKDICT_COMP |
Uncompressed |
block dictionary |
❌ 结构化 |
COMMONDELTA_COMP |
Uncompressed |
int common delta |
❌ 结构化 |
DELTARANGE_COMP |
Uncompressed |
int delta range |
❌ 结构化 |
GCDDELTA |
GCD_Delta |
none |
❌ 无压缩层 |
命名陷阱:
encoding_type是 DDL 层面名称,encodings/compressions是列存储内部名称。注意BLOCKDICT_COMP/COMMONDELTA_COMP/DELTARANGE_COMP这三个带_COMP后缀的编码类型,在内部实现中encodings = 'Uncompressed',实际工作是在compressions层通过结构化压缩完成的——它们虽叫 compression,引擎可以直接运算。只有lzo/zstd这类通用字节流压缩才必须先解压。
1.2 AUTO 编码不是「什么都不做」——它在背后的决策逻辑¶
AUTO 是 Vertica 的默认编码模式,但它不是一种编码类型,而是一个决策代理。 当你未显式指定编码时,Vertica 根据列的数据类型自动选择一种编码+压缩组合。来源:Vertica 性能调优 - 2 使用系统表排除 Vertica 查询性能故障§3.10.2。
| 数据类型 | AUTO 选择的编码 | 典型压缩率 |
|---|---|---|
| INTEGER / NUMERIC(≤18) / DATE / TIMESTAMP | Delta Int Pack(差值编码) | 2:1 ~ 4:1 |
| NUMERIC(≥19) | LZO 通用压缩 | 2:1 ~ 3:1 |
| FLOAT | LZO 通用压缩 | 2:1 ~ 3:1 |
| CHAR / VARCHAR | encodings='String' + compression='lzo' |
2:1 ~ 5:1 |
| BOOLEAN | LZO 通用压缩 | 2:1 ~ 3:1 |
AUTO 的问题:它只看数据类型,不看数据分布。一个只有 5 个 distinct 值的 status 列(INTEGER),AUTO 会选 Delta Int Pack——压缩率约 3:1。但如果显式指定 RLE,压缩率可以轻松达到 100:1 以上。AUTO 对数据一无所知,它只对类型做决策。
1.3 编码类型全景对比¶
以下是 Vertica v26.1.0-2 支持的所有编码类型及其数据适配性(来源:Vertica 性能调优 - 2 使用系统表排除 Vertica 查询性能故障§3.10.2 + Vertica 宽表(多列表)的存储与查询优化§4.2.2):
| 编码类型 | 原理 | 适合的数据特征 | 不适合的场景 | 典型压缩比 |
|---|---|---|---|---|
| RLE(Run-Length Encoding) | 连续相同值替换为 (值, 出现次数) |
低基数(< 1000 distinct)、在 ORDER BY 中已排序的列 | 高基数、未排序的列——RLE 几乎不生效 | 50:1 ~ 100:1 |
| BLOCKDICT_COMP | 每个数据块内建字典,值替换为字典引用 | 低基数、未排序的列(每块 distinct 值少) | 高基数、每块 distinct 值多 | 20:1 ~ 50:1 |
| COMMONDELTA_COMP | 计算相邻值的差值,对差值建字典并用熵编码 | 已排序、有规律间隔的数据(自增 ID、等间隔时间戳) | 无规律的高基数列 | 100:1 ~ 1000:1 |
| DELTAVAL | 每个值记录与块内最小值的差值 | 窄范围整数(如 1~1000) | 范围很宽的整数(差值接近原值) | 5:1 ~ 20:1 |
| GCDDELTA | 基于最大公约数的差值编码 | 整数等差序列(如 1000 的倍数毫秒时间戳) | 非等差序列 | 5:1 ~ 20:1 |
| DELTARANGE_COMP | 记录与前一个值的差值,用范围编码压缩 | 多值浮点/整数列、高基数 | 低基数列(不如 RLE) | 2:1 ~ 5:1 |
| ZSTD_COMP | Zstandard 通用压缩 | 大文本 VARCHAR(>1000)、JSON、日志 | 短文本(ZSTD 开销 > 收益) | 5:1 ~ 10:1 |
| GZIP_COMP | Gzip 通用压缩 | 大文本(同 ZSTD,ZSTD 通常更快) | 同 ZSTD | 5:1 ~ 10:1 |
| AUTO | 按数据类型自动选择(见 1.2) | 不知道选什么时的安全兜底 | 任何需要最佳压缩率的场景 | 2:1 ~ 5:1 |
1.4 排序是编码效率的放大器¶
RLE 和 COMMONDELTA_COMP 的效果严重依赖排序。如果列不在投影的 ORDER BY 子句中,即使显式指定 RLE 编码,同值数据也可能分散在不同的 ROS 容器中,导致运行长度极短,RLE 几乎不生效。
一个直观的类比:RLE 就像「连续相同」的压缩——你必须先把相同的值聚在一起(排序),然后用「×N」代替重复。如果不排序,相同的值散落各处,每个地方都只能说「×1」,压缩效果接近于零。来源:MPP 列存引擎的架构设计哲学§2.4。
在 C-Store 7 Years 论文的真实案例中,一个有 2 亿行、4 列的计量表,Metric 列排序后经 RLE 压缩到了 5 KB——2 亿行变成了一个三元组。来源:MPP 列存引擎的架构设计哲学§2.4。
1.5 编码对 CPU 的双向影响¶
编码不是免费的午餐——编码后的数据在读写和解码时要消耗 CPU。不同编码的 CPU 消耗差异显著(来源:Vertica CPU 持续高负载诊断与优化):
| CPU 消耗排序(低→高) | 编码类型 | CPU 特征 |
|---|---|---|
| 第 1 档 | NONE(不编码) | 几乎无 CPU 开销 |
| 第 2 档 | RLE | 极轻量——run 操作天然高效 |
| 第 3 档 | BLOCKDICT_COMP | 字典查找开销较小 |
| 第 4 档 | DELTAVAL / GCDDELTA | 差值还原需计算 |
| 第 5 档 | COMMONDELTA_COMP / DELTARANGE_COMP | 差值解码 + 字典查找 |
| 第 6 档 | LZO(通用压缩) | 解压 CPU 开销最大 |
关键 trade-off:压缩率越高的编码,不一定 CPU 开销越大。RLE 是一个例外——它既压缩率极高(排序前提下),CPU 开销又极低(run 操作天然简单)。这就是为什么 RLE 是 Vertica 编码优化的「杀手锏」。
第 2 节:系统级监控 — 从宏观了解编码分布¶
2.1 全局编码类型分布统计¶
先从全局视角了解集群中 AUTO 编码占比——AUTO 比例过高是编码策略未优化的直接信号:
-- 全局编码类型分布(按列计数)
SELECT
encoding_type,
COUNT(*) AS column_count,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 1) AS pct
FROM v_catalog.projection_columns
GROUP BY encoding_type
ORDER BY column_count DESC;
如何解读结果:
AUTO占比 > 80%:大部分列使用默认编码,未经过针对性优化。应进一步检查存储量大的表。RLE占比很低(< 10%):可能缺失大量的 RLE 优化机会——低基数排序列是 RLE 的最佳适配场景。BLOCKDICT_COMP/COMMONDELTA_COMP占比极低:这些高级编码未被充分利用。
2.2 按表统计编码效率——找出编码最浪费空间的表¶
以下 SQL 从列存储层面聚合每列的编码和存储情况,帮你找出编码效率最低的表:
-- 按表聚合编码类型和存储占用,定位编码优化候选
SELECT
cs.anchor_table_schema,
cs.anchor_table_name,
COUNT(DISTINCT cs.anchor_table_column_name) AS col_count,
-- AUTO 编码列数
SUM(CASE WHEN pc.encoding_type = 'AUTO' THEN 1 ELSE 0 END) AS auto_cols,
-- RLE 编码列数
SUM(CASE WHEN pc.encoding_type = 'RLE' THEN 1 ELSE 0 END) AS rle_cols,
-- 总存储(GB)
ROUND(SUM(cs.used_bytes) / 1024^3, 2) AS total_gb,
-- AUTO 编码列的存储占比
ROUND(SUM(CASE WHEN pc.encoding_type = 'AUTO' THEN cs.used_bytes ELSE 0 END)
/ NULLIF(SUM(cs.used_bytes), 0) * 100, 1) AS auto_storage_pct
FROM v_monitor.column_storage cs
JOIN v_catalog.projection_columns pc
ON cs.projection_id = pc.projection_id
AND cs.column_id = pc.column_id
GROUP BY 1, 2
HAVING SUM(cs.used_bytes) > 10 * 1024^3 -- 只看 > 10 GB 的表
ORDER BY total_gb DESC
LIMIT 30;
如何解读结果:
auto_storage_pct > 80%且total_gb > 100 GB:这是编码优化的高价值目标。大表 + 高 AUTO 占比 = 巨大的优化空间。rle_cols = 0但col_count > 50:大表缺少 RLE 优化,很可能有低基数排序列可以优化。col_count > 100:宽表需要额外的编码关注——参见Vertica 宽表(多列表)的存储与查询优化。
2.3 逐列查看编码和压缩详情¶
深入到列级别,查看每列的三层编码信息(DDL 编码 + 内部编码 + 压缩):
-- 注意:将 'your_table_name' 替换为实际表名
-- 单表逐列编码详情
SELECT
cs.anchor_table_column_name AS column_name,
pc.data_type,
pc.encoding_type,
cs.encodings AS internal_encoding,
cs.compressions AS internal_compression,
SUM(cs.used_bytes) / 1024^3 AS total_gb,
MAX(cs.ros_count) AS max_ros,
pc.sort_position
FROM v_monitor.column_storage cs
JOIN v_catalog.projection_columns pc
ON cs.projection_id = pc.projection_id
AND cs.column_id = pc.column_id
WHERE cs.anchor_table_schema = 'your_schema_name'
AND cs.anchor_table_name = 'your_table_name'
GROUP BY 1, 2, 3, 4, 5, pc.sort_position
ORDER BY total_gb DESC;
如何解读结果:
total_gb > 1 GB且encoding_type = 'AUTO':该列编码可优化。根据数据类型和基数选择更合适的编码。internal_encoding = 'String'且internal_compression = 'lzo':VARCHAR 列的默认组合。如果该列基数低(如状态码),改用 RLE 收益巨大。sort_position >= 0且encoding_type != 'RLE':排序列未使用 RLE——如果该列同时是低基数,这是最应该优先优化的组合。
第 3 节:逐步定位根因 — 从宏观到微观¶
定位编码策略问题时,按以下四步递进排查。每一步都有明确的「如果不是则进入下一步」的判断条件。
3.1 步骤 1:识别 AUTO 编码的高存储列¶
做什么:找出 AUTO 编码列中存储量最大的前 N 个,优先评估优化收益。
-- TOP 30 AUTO 编码且存储量最大的列
SELECT
cs.anchor_table_schema || '.' || cs.anchor_table_name || '.' || cs.anchor_table_column_name AS full_col_name,
cs.anchor_table_name,
cs.anchor_table_column_name,
pc.data_type,
pc.encoding_type,
cs.encodings,
cs.compressions,
SUM(cs.used_bytes) / 1024^3 AS total_gb,
MAX(cs.ros_count) AS max_ros,
CASE WHEN pc.sort_position >= 0 THEN 'YES' ELSE 'NO' END AS in_sort_order
FROM v_monitor.column_storage cs
JOIN v_catalog.projection_columns pc
ON cs.projection_id = pc.projection_id
AND cs.column_id = pc.column_id
WHERE pc.encoding_type = 'AUTO'
GROUP BY 1, 2, 3, 4, 5, 6, 7, pc.sort_position
ORDER BY total_gb DESC
LIMIT 30;
如何解读:
in_sort_order = 'YES'且total_gb > 1 GB:排序列 + AUTO 编码 + 大存储 = RLE 优化的头号候选人。排序后的数据在编码前已经聚类,RLE 能发挥最大效果。in_sort_order = 'NO'且total_gb > 1 GB:该列存储大但不在排序中。可以考虑调整排序(把该列加入 ORDER BY)或使用 BLOCKDICT_COMP(不依赖排序的字典编码)。data_type为 VARCHAR 且total_gb > 5 GB:大文本列——检查实际数据长度。如果是长文本,考虑 ZSTD_COMP;如果是短文本,确认为什么要这么大存储。
如果不是:如果你没有 AUTO 编码的大存储列(> 1 GB),说明 AUTO 编码在存储维度的浪费不严重。进入下一步检查低基数列的编码选择。
3.2 步骤 2:找出低基数但未用 RLE 的列¶
做什么:RLE 是低基数列的最优编码——存储节省可达 100 倍,CPU 开销极低。这一步检查哪些低基数列错过了 RLE。
-- 注意:将 'your_table_name' 替换为实际表名
-- 检查某表所有非 RLE 编码的列(供人工结合业务知识判断基数)
SELECT
pc.projection_column_name,
pc.data_type,
pc.encoding_type,
pc.sort_position,
SUM(cs.used_bytes) / 1024^2 AS total_mb
FROM v_catalog.projection_columns pc
JOIN v_monitor.column_storage cs
ON pc.projection_id = cs.projection_id
AND pc.column_id = cs.column_id
WHERE pc.table_schema = 'public'
AND pc.table_name = 'your_table_name'
AND pc.encoding_type != 'RLE'
GROUP BY 1, 2, 3, 4
ORDER BY total_mb DESC;
如何解读:
- 从输出中找到
sort_position >= 0(在排序中)且total_mb > 500 MB的列。然后结合你对数据的了解——如果该列 distinct 值 < 1000,转换为 RLE 编码。 - 如果没有这类列,进入下一步。
判断基数的快捷方法(抽样,不精确但快速):
输出 < 1000 → RLE 大概率是更好选择。
3.3 步骤 3:检查自增 ID / 时间戳列的编码选择¶
做什么:自增 ID(如 BIGINT 主键)和等间隔时间戳是 COMMONDELTA_COMP 的最佳场景——压缩比可达 100:1 ~ 1000:1。
-- 注意:将 'your_table_name' 替换为实际表名
-- 检查某表适合 COMMONDELTA_COMP / GCDDELTA 的列(整数/时间类)
SELECT
pc.projection_column_name,
pc.data_type,
pc.encoding_type,
pc.sort_position,
SUM(cs.used_bytes) / 1024^2 AS total_mb
FROM v_catalog.projection_columns pc
JOIN v_monitor.column_storage cs
ON pc.projection_id = cs.projection_id
AND pc.column_id = cs.column_id
WHERE pc.table_schema = 'public'
AND pc.table_name = 'your_table_name'
AND ( pc.data_type IN ('int', 'bigint', 'integer', 'timestamp', 'timestamptz', 'date', 'time')
OR pc.data_type ILIKE 'numeric(%,0)' -- NUMERIC 无小数位,等同于整数
)
AND pc.sort_position >= 0 -- 在排序中
AND pc.encoding_type NOT IN ('COMMONDELTA_COMP', 'GCDDELTA')
GROUP BY 1, 2, 3, 4
ORDER BY total_mb DESC;
如何解读:
data_type为int/bigint或numeric(%,0)(无小数 NUMERIC),且在排序中,且encoding_type为 AUTO/DELTAVAL:如果该列是自增 ID(值连续递增),COMMONDELTA_COMP 比 DELTAVAL 的压缩率高 5~10 倍。data_type为timestamp/timestamptz/date/time,且encoding_type为 AUTO:等间隔时间序列(如每小时一条记录)也适合COMMONDELTA_COMP。total_mb > 500 MB:存储量足够大,值得优化。
如果不是:列都不在此范围内,进入最后一步。
3.4 步骤 4:检查是否有大文本列应使用 ZSTD_COMP¶
做什么:VARCHAR(>1000) 的大文本列(日志、JSON、描述字段),AUTO 默认使用 String + LZO。显式指定 ZSTD_COMP 或 GZIP_COMP 可获得 5:1 ~ 10:1 的压缩率。
-- 检查大文本列的编码
SELECT
c.table_schema,
c.table_name,
c.column_name,
c.data_type,
c.data_type_length,
pc.encoding_type,
SUM(cs.used_bytes) / 1024^2 AS total_mb
FROM v_catalog.columns c
JOIN v_catalog.tables t
ON c.table_id = t.table_id AND c.table_schema = t.table_schema
JOIN v_catalog.projection_columns pc
ON c.table_id = pc.table_id AND c.column_name = pc.table_column_name
JOIN v_monitor.column_storage cs
ON pc.projection_id = cs.projection_id AND pc.column_id = cs.column_id
WHERE t.is_system_table = false AND t.is_temp_table = false
AND c.data_type ILIKE 'varchar%'
AND c.data_type_length > 500
AND pc.encoding_type = 'AUTO'
AND pc.projection_id IN (SELECT MIN(projection_id) FROM v_catalog.projection_columns pc2
WHERE pc2.table_id = pc.table_id AND pc2.table_column_name = pc.table_column_name)
GROUP BY 1, 2, 3, 4, 5, 6
ORDER BY total_mb DESC
LIMIT 20;
如何解读:
total_mb > 500 MB且data_type_length > 1000:强烈建议改用 ZSTD_COMP。data_type_length = 65000:定义严重过大——除了改编码,还要考虑缩小列定义(详见Vertica 列数据类型与长度优化)。
第 4 节:解决方案 — 从快速见效到根本治理¶
编码优化的三种方式(按侵入性从低到高):
| 方式 | 侵入性 | 适用场景 | 耗时 |
|---|---|---|---|
方式 A:ALTER TABLE ... ALTER COLUMN ... SET ENCODING |
低(元数据变更,需等待 mergeout) | 单列/少表、数据量不大 | 中 |
方式 B:Database Designer (DESIGNER_DESIGN_PROJECTION_ENCODINGS) |
低 | 整库/多表批量优化 | 中-长 |
| 方式 C:新建表 + INSERT...SELECT + 删旧表 | 高(数据重写) | 多列同时修改、跨 storage class 变更 | 长 |
4.1 方式 A:手动显式指定编码(单列修复)¶
当你明确知道某列应该用什么编码时,直接指定:
-- 将 status 列改为 RLE 编码(需指定受影响的投影名)
ALTER TABLE public.your_table
ALTER COLUMN status
SET ENCODING RLE
PROJECTIONS (your_table_b0, your_table_b1);
-- 将 order_id 改为 COMMONDELTA_COMP
ALTER TABLE public.your_table
ALTER COLUMN order_id
SET ENCODING COMMONDELTA_COMP
PROJECTIONS (your_table_b0, your_table_b1);
-- 将 description 大文本列改为 ZSTD_COMP
ALTER TABLE public.your_table
ALTER COLUMN description
SET ENCODING ZSTD_COMP
PROJECTIONS (your_table_b0, your_table_b1);
注意事项:
- PROJECTIONS 子句是语法强制项。
ALTER COLUMN SET ENCODING必须跟PROJECTIONS (...)列出目标投影,省略会直接报语法错误(而非静默跳过)。注意不支持ALL PROJECTIONS关键字——必须显式列出投影名或 basename。 - 投影名可以用 basename 或全名。写
PROJECTIONS (your_table_b0)会更新该投影及所有 buddy(分段投影自动传播);写PROJECTIONS (your_table)(basename)会更新共享该 basename 的所有投影。后者更省事——不用逐一列出 b0、b1。 - 如果列在某个投影中不存在,语句直接报错。建议先确认:
SELECT DISTINCT projection_name FROM v_catalog.projection_columns WHERE table_column_name = 'your_column'; - 编码变更后新写入数据立即用新编码,已有数据在 mergeout 时自动重新编码。
ALTER COLUMN SET ENCODING是元数据变更——新 ROS 容器用新编码写入,旧 ROS 容器在 Tuple Mover 执行 mergeout 时逐步重编码。如需加速:SELECT DO_TM_TASK('mergeout', 'table_name');。 - 大表的 mergeout 耗时长(数百 GB 的表可能耗时数小时),应在计划窗口执行。
- 如果不想等 mergeout,可以直接用 4.3 方式 C(新建表+迁移),新建表时数据直接按新编码写入。
4.2 方式 B:Database Designer(批量优化)¶
当你有一批表需要优化,且不确定每列最优编码时,让 DBD 基于数据采样自动决策。DBD 会对每列尝试不同编码类型,选择占用存储最少的那个。
-- 对单表运行 encoding 分析(deploy=false 仅生成脚本,不实际修改)
SELECT DESIGNER_DESIGN_PROJECTION_ENCODINGS(
'public.your_table_name', -- 表名(也可用投影名、schema.* 或 ''=全库)
'', -- 输出到 stdout;写文件名则保存到 catalog 目录
false, -- deploy=false:仅分析,不部署
true -- reanalyze-encodings=true:忽略现有编码,重新分析
);
参数说明(来源:官方文档):
| 参数 | 含义 | 常见用法 |
|---|---|---|
proj-spec |
投影/表/schema 名,'' = 全库 |
'public.my_table' |
destination |
'' = 输出到 stdout;'filename' = 保存到 catalog 目录 |
'' 直接在 vsql 看到 SQL 脚本 |
deploy |
true = 实际修改编码;false = 仅生成脚本 |
先 false 审查,确认后再 true |
reanalyze-encodings |
true = 忽略现有编码全部重新分析;false = 跳过已有编码的列 |
首次优化用 true,后续微调用 false |
⚠️ 没有 dry_run 参数。deploy=false 就是 dry run——只生成 SQL 脚本不执行。不要把 deploy=true 当成分析模式,那会直接修改投影编码。
DBD 的工作原理(来源:Vertica 性能调优 - 3 重新设计 PROJECTION§1.2):
- 对每个投影列抽取 1% 数据样本
- 枚举候选编码类型并测量每种编码后的存储大小
- 选择占用存储最少的编码作为建议
DESIGNER_DESIGN_PROJECTION_ENCODINGS只优化编码,不会改变排序和分段——它不会重构投影结构。如果需要同时优化排序、分段和编码,应使用完整的 Database Designer(DESIGNER_CREATE_DESIGN/DESIGNER_RUN_POPULATE_DESIGN_AND_DEPLOY),它会创建全新的投影设计
何时用 DBD,何时手选:
| 场景 | 推荐方式 |
|---|---|
| 大表(100+ 列),不确定每列最优编码 | DBD |
| 明确知道某列基数低应改为 RLE | 手动 ALTER COLUMN |
| 需要变更全库数百张表的编码 | DBD 批量 + 分批部署 |
| 对 DBD 建议不满意,想微调 | DBD 生成脚本后手动修改再部署 |
4.3 方式 C:新建表 + 迁移数据(最彻底)¶
当大量列需要同时改编码,或者需要配合列定义变更(如 NUMERIC(38,10) → NUMERIC(18,6),跨 storage class)时,新建表比逐列 ALTER 更高效。
-- 已验证:Vertica v26.1.0-2
-- 1. 导出目标表的完整 DDL(含投影编码),编辑导出的 CREATE TABLE 手动改编码
SELECT EXPORT_OBJECTS('', 'public.your_table_name');
-- 2. 用修改编码后的 DDL 建新表(ORDER BY + SEGMENTED BY 自动创建 b0/b1)
CREATE TABLE public.your_table_new (
id BIGINT NOT NULL,
status VARCHAR(20) ENCODING RLE,
order_date DATE ENCODING COMMONDELTA_COMP,
amount NUMERIC(18,4),
description VARCHAR(2000) ENCODING ZSTD_COMP,
-- ... 其他列
created_at TIMESTAMP
)
ORDER BY order_date, status
SEGMENTED BY HASH(id) ALL NODES;
-- 3. 一次 INSERT ... SELECT 迁移所有数据
INSERT INTO public.your_table_new
SELECT id, status, order_date, amount, description, created_at
FROM public.your_table_old;
COMMIT;
-- 4. 删旧表,重命名新表
DROP TABLE public.your_table_old CASCADE;
ALTER TABLE public.your_table_new RENAME TO your_table_old;
为什么这样做:新表的投影在创建时按显式编码写入数据,避免了 ALTER COLUMN + 等待 mergeout 的耗时。
4.4 编码选择决策树¶
当你不确定一列该用什么编码时,按以下决策树判断:
列的数据特征
├── 低基数(distinct < 1000)且在 ORDER BY 中?
│ └── YES → RLE(压缩比最高,CPU 最低)
├── 低基数(distinct < 1000)但不在 ORDER BY 中?
│ └── YES → BLOCKDICT_COMP(不依赖排序的字典编码)
├── 自增/连续值(ID、等间隔时间戳)?
│ ├── 等差序列 → GCDDELTA
│ └── 连续但非等差 → COMMONDELTA_COMP
├── 窄范围整数(如 1~1000)?
│ └── YES → DELTAVAL
├── 大文本(VARCHAR > 1000)?
│ └── YES → ZSTD_COMP(比 GZIP 快)或 GZIP_COMP
├── 高基数浮点/整数,每块值很多?
│ └── YES → DELTARANGE_COMP
└── 以上都不适用?
└── 保持 AUTO(安全兜底)
4.5 编码选择时的常见陷阱¶
陷阱 1:以为 RLE 对所有低基数列都有效。 RLE 依赖数据物理有序——相同值必须连续存放。如果低基数列不在 ORDER BY 中,RLE 几乎不会压缩。此时 BLOCKDICT_COMP 是更好的选择,因为它对每个数据块(通常几百到几千行)独立建字典,不依赖全局排序。
陷阱 2:对高基数列使用 RLE。 如果列有 100 万个 distinct 值,每个值的 run length 几乎为 1——RLE 退化为「存储原值 + 运行长度 1」,压缩效果接近于零。RLE 只适合重复率高的列(平均 run length > 10)。
陷阱 3:过度优化编码而忽略排序。 编码是排序的放大器,不是替代品。如果你花大量时间微调编码但不优化排序,收益可能只有 10%;反过来先优化排序再调整编码,收益可能 10 倍。
陷阱 4:在所有投影上同时改编码。
如果你改了编码但没有在所有投影上同步执行 SET ENCODING,不同投影上同一列的新旧编码会共存,查询时优化器选择的投影不同,结果可能不一致(虽然逻辑正确但查询计划不同)。
第 5 节:深入案例¶
5.1 案例 1:低基数排序列从 AUTO 到 RLE——存储降低 98%¶
📝 虚构案例
场景描述:某电商平台订单表 orders 有 50 亿行,包含 order_status(6 个值)、payment_method(8 个值)、shipping_province(31 个值)等低基数列。大部分业务列使用 AUTO 编码,order_date 已由 DBD 优化为 COMMONDELTA_COMP。投影按 order_date, order_status 排序。表存储约 120 GB。
诊断过程:
-- 检查低基数排序列的编码类型
SELECT projection_column_name, encoding_type, sort_position, data_type
FROM v_catalog.projection_columns
WHERE table_schema = 'public'
AND table_name = 'orders'
AND sort_position >= 0
ORDER BY sort_position;
输出:
projection_column_name | encoding_type | sort_position | data_type
-----------------------+---------------+--------------+-----------
order_date | COMMONDELTA_COMP | 0 | date
order_status | AUTO | 1 | varchar(20)
order_id | AUTO | 2 | bigint
order_status 按 AUTO 编码,encodings='String' + compressions='lzo',存储 18 GB。
根因分析:order_status 只有 6 个 distinct 值,且在排序中(sort_position=1),是 RLE 的完美候选。AUTO 无法感知低基数特征,默认用 String + LZO——只压缩了约 3:1。
修复方案:
ALTER TABLE public.orders
ALTER COLUMN order_status
SET ENCODING RLE
PROJECTIONS (orders_b0, orders_b1);
-- 已有数据在 mergeout 时自动重新编码,也可手动触发加速:
SELECT DO_TM_TASK('mergeout', 'orders');
效果对比:
| 指标 | 优化前(AUTO) | 优化后(RLE) | 变化 |
|---|---|---|---|
order_status 列存储 |
18 GB | 0.35 GB | ↓ 98% |
| 表总存储 | 120 GB | 102 GB | ↓ 15% |
WHERE order_status = ? 扫描速度 |
全列扫描 | RLE 谓词直接定位 run | 提速 3-5 倍 |
5.2 案例 2:宽表编码全面优化——从 320 GB 降到 68 GB¶
📝 虚构案例
场景描述:某金融机构风控系统的「借款人特征宽表」包含 500 列,约 2000 万行。所有列使用 AUTO 编码。批量评分 SQL(SELECT *)扫描全表耗时超 30 分钟。
诊断过程:用第 3.1 节 SQL 找到存储量最大的 AUTO 编码列(共 150 列 > 500 MB),然后按第 3.2~3.4 节逐步分类:
- 低基数且排序中的列(80 列):如
credit_level(5 个值)、marital_status(4 个值)等,改为 RLE - 自增/连续值列(12 列):如
feature_id(自增 BIGINT),改为 COMMONDELTA_COMP - 大文本列(5 列):如
credit_report_json(VARCHAR(10000)),改为 ZSTD_COMP - 窄范围整数列(20 列):如
age(18-75)、credit_score(300-850),改为 DELTAVAL - 浮点高基数列(33 列):如各种评分和概率值,保持 AUTO(当前最优)
修复方案:
ALTER TABLE public.borrower_features ALTER COLUMN credit_level SET ENCODING RLE PROJECTIONS (borrower_features_b0, borrower_features_b1);
ALTER TABLE public.borrower_features ALTER COLUMN marital_status SET ENCODING RLE PROJECTIONS (borrower_features_b0, borrower_features_b1);
ALTER TABLE public.borrower_features ALTER COLUMN feature_id SET ENCODING COMMONDELTA_COMP PROJECTIONS (borrower_features_b0, borrower_features_b1);
ALTER TABLE public.borrower_features ALTER COLUMN credit_report_json SET ENCODING ZSTD_COMP PROJECTIONS (borrower_features_b0, borrower_features_b1);
ALTER TABLE public.borrower_features ALTER COLUMN age SET ENCODING DELTAVAL PROJECTIONS (borrower_features_b0, borrower_features_b1);
-- ... 已有数据等待 mergeout 自动重新编码
效果对比:
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 表总存储 | 320 GB | 68 GB | ↓ 79% |
| 批量评分耗时 | > 30 min | 4.2 min | ↓ 86% |
| Scan 磁盘读取 | 156 GB | 42 GB | ↓ 73% |
| peak file handles | 9500 | 520 | ↓ 95% |
| 80 个低基数列存储 | 180 GB | 12 GB | ↓ 93%(RLE 效果) |
5.3 案例 3:某省级运营商 570 张表编码优化——全库压缩率从 2.4x 跃升到 3.44x¶
📋 真实案例 · 来源:20230324某省级运营商集市库 BIZ_MART 表编码压缩优化报告
场景描述:某省级运营商集市库 BIZ_MART(17 节点 × 15TB/节点,Vertica v11.1.1-14),在 2023 年 3 月发现集群存储使用率达到 76.9%(182TB),已接近 80% 告警线。优化前全库压缩率仅 2.4 倍。
诊断过程:DBA 按表大小排序,对各表的投影列进行编码分析,识别可以优化的编码类型。
修复方案:分 5 天对 570 张表(约 116TB 数据)执行编码优化。
效果对比:
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 全库压缩数据 | 182 TB | 131 TB | ↓ 51 TB(-28%) |
| 裸数据量 | 439 TB | 458 TB | +4%(数据自然增长) |
| 全库压缩率 | 2.4× | 3.44× | +43% |
| 节点平均使用率 | 76.9% | 55.6% | -21.3pp |
| TOP 50 表平均压缩率 | 2.46× | 5.26× | +114% |
| TOP 50 表存储 | 59 TB | 33 TB | -44% |
关键细节:裸数据量增长了 4%(数据自然写入),但压缩数据反而下降了 28%——说明编码优化不仅抵消了新数据增长,还额外释放了大量存储空间。
查询性能影响:编码优化前后数据库整体性能无明显变化,均在毫秒级。这说明从 AUTO 切换到更激进的编码(如 RLE、BLOCKDICT_COMP)并没有增加查询时的解码开销——RLE 和 DELTAVAL 等编码的解码 CPU 开销与 LZO 通用压缩相当甚至更低。
第 6 节:完整诊断流程实战¶
📝 虚构场景 · 完整演练
背景:某运营商经分系统,3 节点 Vertica 集群(每节点 256 GB 内存)。DBA 收到告警——节点存储使用率超过 80%。你需要在一个工作日内完成编码优化诊断和初步修复。
时间线¶
| 时间 | 动作 | 发现 |
|---|---|---|
| 09:00 | 收到存储使用率 > 80% 告警 | 节点 v_node0001 使用率 83%,最紧迫 |
| 09:15 | 执行 2.1 节全局编码分布 SQL | 全库 3500 列中 AUTO 占比 87%——问题确认 |
| 09:30 | 执行 2.2 节按表统计编码效率 SQL | 发现 cdr_daily 表 150 GB,AUTO 占比 95% |
| 09:45 | 进入第 3 节逐步定位 |
Step 1 — 识别 AUTO 编码的高存储列(3.1):
输出摘要(top 5 列):
| column_name | data_type | encoding_type | total_gb | in_sort_order |
|---|---|---|---|---|
| calling_number | varchar(20) | AUTO | 22.3 | YES |
| called_number | varchar(20) | AUTO | 21.8 | YES |
| call_type | varchar(10) | AUTO | 18.5 | YES |
| imsi | varchar(15) | AUTO | 15.2 | NO |
| start_time | timestamp | AUTO | 14.1 | YES |
判断:call_type(通话类型,如 01/02/03 共 4 个值)和 start_time(按时间排序)是编码优化的明确目标。
Step 2 — 确认低基数列(3.2):
SELECT COUNT(DISTINCT call_type) FROM cdr_daily TABLESAMPLE(1);
-- 输出:4
SELECT COUNT(DISTINCT calling_number) FROM cdr_daily TABLESAMPLE(1);
-- 输出:1520000
判断:call_type(4 个 distinct)→ RLE。calling_number(150 万 distinct)→ 高基数,保持 AUTO 或考虑 DELTARANGE_COMP。
Step 3 — 检查时间戳列(3.3):
start_time 是通话开始时间,已排序,等间隔不严格(通话时间随机),不完全适合 COMMONDELTA_COMP。但如果是按小时的聚合数据,则需要进入这一步。当前场景下保持 AUTO 即可。
Step 4 — 执行修复:
-- 对 cdr_daily 的低基数列执行 RLE 编码
ALTER TABLE public.cdr_daily
ALTER COLUMN call_type SET ENCODING RLE
PROJECTIONS (cdr_daily_b0, cdr_daily_b1);
SELECT DO_TM_TASK('mergeout', 'cdr_daily');
mergeout 由 Tuple Mover 在后台执行,不阻塞业务。也可等待 TM 按正常周期自动触发。
Step 5 — 效果验证:
-- 验证编码是否生效
SELECT encoding_type, SUM(used_bytes)/1024^3 AS gb
FROM v_catalog.projection_columns pc
JOIN v_monitor.column_storage cs
ON pc.projection_id = cs.projection_id AND pc.column_id = cs.column_id
WHERE pc.table_schema = 'public'
AND pc.table_name = 'cdr_daily'
AND pc.table_column_name = 'call_type'
GROUP BY encoding_type;
-- 输出:encoding_type = 'RLE', gb = 0.85(从 18.5 GB 降到 0.85 GB)
最终效果:
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
cdr_daily.call_type 存储 |
18.5 GB | 0.85 GB | ↓ 95% |
| 该列磁盘 I/O(估算) | ~18.5 GB/扫描 | ~0.85 GB/扫描 | ↓ 95% |
查询 WHERE call_type = '01' 耗时 |
12 秒 | 2.5 秒 | ↓ 79% |
这只是第一个工作日的结果——仅优化了 1 列表。按同样方法继续优化
cdr_daily的call_status、roam_type等其他低基数列和另外数十张大表,预计整体可释放 30-40% 的存储。
第 7 节:快速诊断 SQL 工具箱¶
| # | 诊断目标 | SQL(已验证:Vertica v26.1.0-2) |
|---|---|---|
| 1 | 全局编码类型分布 | SELECT encoding_type, COUNT(*) AS col_count, ROUND(COUNT(*)*100.0/SUM(COUNT(*)) OVER(),1) AS pct FROM v_catalog.projection_columns GROUP BY encoding_type ORDER BY col_count DESC; |
| 2 | 按表统计编码效率(> 10 GB 表) | SELECT cs.anchor_table_schema, cs.anchor_table_name, COUNT(DISTINCT cs.anchor_table_column_name) AS col_count, SUM(CASE WHEN pc.encoding_type='AUTO' THEN 1 ELSE 0 END) AS auto_cols, ROUND(SUM(cs.used_bytes)/1024^3,2) AS total_gb, ROUND(SUM(CASE WHEN pc.encoding_type='AUTO' THEN cs.used_bytes ELSE 0 END)/NULLIF(SUM(cs.used_bytes),0)*100,1) AS auto_storage_pct FROM v_monitor.column_storage cs JOIN v_catalog.projection_columns pc ON cs.projection_id=pc.projection_id AND cs.column_id=pc.column_id GROUP BY 1,2 HAVING SUM(cs.used_bytes) > 10*1024^3 ORDER BY total_gb DESC LIMIT 30; |
| 3 | 单表逐列编码+存储详情 | SELECT cs.anchor_table_column_name, pc.data_type, pc.encoding_type, cs.encodings, cs.compressions, SUM(cs.used_bytes)/1024^2 AS total_mb, MAX(cs.ros_count) AS max_ros, CASE WHEN pc.sort_position>=0 THEN 'YES' ELSE 'NO' END AS in_sort_order FROM v_monitor.column_storage cs JOIN v_catalog.projection_columns pc ON cs.projection_id=pc.projection_id AND cs.column_id=pc.column_id WHERE cs.anchor_table_schema='public' AND cs.anchor_table_name=':table_name' GROUP BY 1,2,3,4,5,pc.sort_position ORDER BY total_mb DESC; |
| 4 | AUTO 编码高存储列(全局 TOP 30) | SELECT cs.anchor_table_name, cs.anchor_table_column_name, pc.data_type, pc.encoding_type, SUM(cs.used_bytes)/1024^3 AS total_gb, CASE WHEN pc.sort_position>=0 THEN 'YES' ELSE 'NO' END AS in_sort FROM v_monitor.column_storage cs JOIN v_catalog.projection_columns pc ON cs.projection_id=pc.projection_id AND cs.column_id=pc.column_id WHERE pc.encoding_type='AUTO' GROUP BY 1,2,3,4,pc.sort_position ORDER BY total_gb DESC LIMIT 30; |
| 5 | 非 RLE 编码的所有列(含排序和未排序) | SELECT pc.projection_column_name, pc.data_type, pc.encoding_type, pc.sort_position, SUM(cs.used_bytes)/1024^2 AS total_mb FROM v_catalog.projection_columns pc JOIN v_monitor.column_storage cs ON pc.projection_id=cs.projection_id AND pc.column_id=cs.column_id WHERE pc.table_schema='public' AND pc.table_name=':table_name' AND pc.encoding_type!='RLE' GROUP BY 1,2,3,4 ORDER BY total_mb DESC; |
| 6 | BDC/时间戳列的编码检查 | SELECT pc.projection_column_name, pc.data_type, pc.encoding_type, pc.sort_position, SUM(cs.used_bytes)/1024^2 AS total_mb FROM v_catalog.projection_columns pc JOIN v_monitor.column_storage cs ON pc.projection_id=cs.projection_id AND pc.column_id=cs.column_id WHERE pc.table_schema='public' AND pc.table_name=':table_name' AND (pc.data_type IN ('int','bigint','integer','timestamp','timestamptz','date','time') OR pc.data_type ILIKE 'numeric(%,0)') AND pc.sort_position>=0 AND pc.encoding_type NOT IN ('COMMONDELTA_COMP','GCDDELTA') GROUP BY 1,2,3,4 ORDER BY total_mb DESC; |
| 7 | 大文本列使用 AUTO 编码 | SELECT c.table_schema, c.table_name, c.column_name, c.data_type_length, pc.encoding_type, SUM(cs.used_bytes)/1024^2 AS total_mb FROM v_catalog.columns c JOIN v_catalog.tables t ON c.table_id=t.table_id AND c.table_schema=t.table_schema JOIN v_catalog.projection_columns pc ON c.table_id=pc.table_id AND c.column_name=pc.table_column_name JOIN v_monitor.column_storage cs ON pc.projection_id=cs.projection_id AND pc.column_id=cs.column_id WHERE t.is_system_table=false AND t.is_temp_table=false AND c.data_type ILIKE 'varchar%' AND c.data_type_length>500 AND pc.encoding_type='AUTO' AND pc.projection_id IN (SELECT MIN(projection_id) FROM v_catalog.projection_columns pc2 WHERE pc2.table_id=pc.table_id AND pc2.table_column_name=pc.table_column_name) GROUP BY 1,2,3,4,5 ORDER BY total_mb DESC LIMIT 20; |
| 8 | DBD 编码分析(单表,仅生成脚本) | SELECT DESIGNER_DESIGN_PROJECTION_ENCODINGS('public.:table_name', '', false, true); — deploy=false 是 dry run,第三个参数不要设成 true |
| 9 | 手动改编码(单列 RLE) | ALTER TABLE public.:table_name ALTER COLUMN :col_name SET ENCODING RLE PROJECTIONS (:proj_b0, :proj_b1); |
| 10 | 手动触发 mergeout 加速重编码 | SELECT DO_TM_TASK('mergeout', ':table_name'); — 或等待 Tuple Mover 自动触发 |
第 8 节:最佳实践清单¶
按投入产出比从高到低排列:
- 低基数列 + 在 ORDER BY 中 = 立即改为 RLE — 这是 Vertica 编码优化中收益最大的单步操作。一个 6 个 distinct 值的排序列,AUTO(String + LZO)→ RLE 后存储可降 95%+,CPU 开销反而更低(RLE 解码极轻量)。前提是
COUNT(DISTINCT) < 1000且在sort_position >= 0。 - AUTO 占比 > 80% 是编码优化的强烈信号 — 如果全库 AUTO 占比超过 80%,说明几乎没有做过编码优化。运行第 7 节 SQL #1 确认全局分布,然后按表大小排序逐表推进。
- 让 DBD 做批量决策,不要逐列猜测 — 面对 100+ 列的表,逐个手动判断编码类型既耗时又容易出错。运行
DESIGNER_DESIGN_PROJECTION_ENCODINGS()让 DBD 基于数据采样自动决策,然后审核 DBD 建议而非从零开始。 - 排序先于编码——先调整 ORDER BY,再选编码 — 编码是排序的放大器。如果列不在排序中,RLE 几乎无效。在设计新投影时,先确定排序键满足查询需求,再为排序列选择编码。
- 自增 ID / 等间隔时间戳 = COMMONDELTA_COMP — 自增 BIGINT 主键和等间隔时间戳是 COMMONDELTA_COMP 的完美适配场景。压缩比可达 100:1 ~ 1000:1,远超 AUTO 的 Delta Int Pack(2:1 ~ 4:1)。
- 大文本列(VARCHAR > 1000)显式指定 ZSTD_COMP,不要靠 AUTO — AUTO 对大文本列默认使用 String + LZO,压缩率约 2:1 ~ 5:1。显式指定 ZSTD_COMP 可达到 5:1 ~ 10:1,且解压速度与 LZO 相当。
- 编码优化不会立即对已有数据生效——需等待 mergeout 或重建投影 —
ALTER COLUMN ... SET ENCODING是元数据变更,新写入的 ROS 容器立即使用新编码。已有 ROS 容器在 Tuple Mover 执行 mergeout 时自动重新编码。如需加速可手动触发SELECT DO_TM_TASK('mergeout', 'table_name');,或直接新建表迁移数据。 - 不要对高基数列用 RLE — 如果列有 100 万个 distinct 值,RLE 的运行长度几乎为 1——编码后比原值更大。RLE 只适合平均 run length > 10 的列。
- 编码变更后对比存储大小,验证收益 — 使用第 7 节 SQL #3 对比同一列 mergeout 前后的
total_mb,确认编码优化达到了预期效果。如果存储没什么变化,说明编码选错了——重新评估。 - AUTO 不是「什么都不做」——它在你看不到的地方做了选择 — 了解每一列的 AUTO 实际选择了什么编码(通过
column_storage.encodings+compressions),你才能判断这个选择是否正确。盲目信任 AUTO = 放弃 50% 以上的压缩潜力。
扩展阅读¶
- MPP 列存引擎的架构设计哲学 — 编码在列存五级演进中的位置与原理
- Vertica 列数据类型与长度优化 — 数据类型定义如何限制编码选择
- Vertica CPU 持续高负载诊断与优化 — 编码对 CPU 的双向影响
- Vertica 性能调优 - 2 使用系统表排除 Vertica 查询性能故障 — 编码类型参考表与诊断 SQL
- Vertica 性能调优 - 3 重新设计 PROJECTION — 编码在投影设计中的角色
- Vertica 宽表(多列表)的存储与查询优化 — 宽表场景下的编码策略与文件句柄优化
本文以 Vertica v26.1.0-2 为验证基准。编码类型的可用性和默认行为可能随版本略有差异,建议在实际操作前先确认当前版本的 encoding_type 枚举值。