Vertica 查询 Spill 到磁盘的原因与优化¶
作者:JiangChong | 发布时间:2026-04-08
适用场景:查询执行时间异常长但 CPU 并不高,
query_events中出现GROUP_BY_SPILLED或JOIN_SPILLED,execution_engine_profiles中cumulative size of raw temp data显著大于 0。关联:Vertica 内存压力诊断与调优 | Vertica 资源池最佳实践 | Vertica 性能调优 - 2 使用系统表排除 Vertica 查询性能故障 | Vertica CPU 持续高负载诊断与优化
理解全文脉络¶
Spill 是 Vertica 查询性能的「隐形杀手」——查询不会报错、不会拒绝,只是悄悄地变慢。本文从 Spill 的底层机制讲起,逐步展开如何检测、如何量化、如何根除。如果你已经确认查询有 GROUP_BY_SPILLED 事件,可以直接跳到第 4 节看修复方案。
1. 理解 Spill:查询为什么会溢出到磁盘¶
1.1 Spill 的本质¶
在 Vertica 中,Spill 指的是查询算子在内存中无法完成计算,被迫将数据写入磁盘临时文件,然后通过外部排序或归并算法继续处理。这不是 Bug——它是 Vertica 的一种降级策略:当内存不够时,用磁盘空间换取继续执行的能力,而不是直接报错。
两种最常见的 Spill 类型:
| Spill 类型 | 触发条件 | 后果 |
|---|---|---|
GROUP_BY_SPILLED |
GroupByHash 算子的哈希表超过了可用内存 |
哈希表中的数据溢出到磁盘,改为外部排序聚合 |
JOIN_SPILLED |
JoinHash 算子的内表哈希表超过了可用内存 |
退化为外部归并连接,需要先排序再归并 |
还有较少见的 WOS_SPILL(WOS 写满溢出到 ROS),但 WOS Spill 是数据加载层面的问题,不涉及查询性能,不在本文讨论范围。
1.2 Spill 的发生机制¶
以 GROUP BY region, category, SUM(amount) 为例,看 Vertica 的处理流程:
正常情况(无 Spill):
- Scan 算子从磁盘读取数据并解压
- 数据进入
GroupByHash算子 - 算子根据
GROUP BY列计算哈希值,将每行数据放入对应的哈希桶 - 哈希桶在内存中累积数据,直到所有数据都处理完
- 输出每个桶的聚合结果
Spill 情况(内存不足):
1-3 同上。但当哈希桶越来越大,算子发现内存不够用时: 4. 将当前内存中最大的哈希桶「溢出」到磁盘临时文件 5. 清空该桶的内存空间,继续接收新数据 6. 所有数据处理完后,将磁盘上的溢出数据读回,排序后聚合 7. 最终与内存中剩余桶的结果合并输出
关键代价:Spill 不仅增加了磁盘 I/O(慢),还引入了额外的排序操作(CPU 密集)。一次 Spill 可能让查询执行时间增加 3-10 倍。
1.3 为什么 Spill 如此常见¶
Spill 在 Vertica 中非常普遍,核心原因是:
- 默认
query_budget偏保守:general 池的默认query_budget通常只有几 GB,而真实的分析查询处理上亿行数据时,哈希表可能轻松超过 10GB。 - 统计信息缺失:优化器依赖统计信息估算内存需求。如果统计信息不准,它可能严重低估了
GroupByHash需要的哈希表大小。 - MPP 架构的「加和效应」:每个节点的查询都独立分配
query_budget。在 5 节点集群上,同样的查询需要 5 倍的节点间网络传输后的内存。
2. 检测 Spill:如何证明查询在溢出¶
2.1 方法一:query_events(最快)¶
PROFILE 执行查询后,直接查看是否有 Spill 事件:
SELECT event_type,
operator_name,
path_id,
event_description,
suggested_action
FROM v_monitor.query_events
WHERE transaction_id = :t_id
AND statement_id = :s_id
AND event_type IN ('GROUP_BY_SPILLED', 'JOIN_SPILLED');
如果返回 > 0 行,说明发生了 Spill。suggested_action 会给出优化建议,例如:
GROUP_BY_SPILLED → "Consider a sorted projection. Increase memory available to the plan."
JOIN_SPILLED → "Consider a different join order or increase memory."
2.2 方法二:execution_engine_profiles(量化严重度)¶
query_events 只能告诉你「是否有 Spill」,但无法告诉你「有多严重」——是溢出了 10MB 还是 10GB?需要从计数器获取。
SELECT operator_name,
path_id,
SUM(DECODE(counter_name, 'cumulative size of raw temp data (bytes)', counter_value, NULL)) AS spill_bytes,
SUM(DECODE(counter_name, 'memory reserved (bytes)', counter_value, NULL)) AS mem_reserved_bytes,
SUM(DECODE(counter_name, 'rows produced', counter_value, NULL)) AS rows_produced
FROM v_monitor.execution_engine_profiles
WHERE transaction_id = :t_id
AND statement_id = :s_id
AND counter_name IN ('cumulative size of raw temp data (bytes)', 'memory reserved (bytes)', 'rows produced')
GROUP BY operator_name, path_id
HAVING SUM(DECODE(counter_name, 'cumulative size of raw temp data (bytes)', counter_value, NULL)) > 0
ORDER BY spill_bytes DESC;
严重度判断:
spill_bytes 规模 |
严重度 | 行动 |
|---|---|---|
| < 1 GB | 轻微 | 可接受,查询仍能在合理时间完成 |
| 1-10 GB | 中等 | 查询会明显变慢(2-5 倍),建议优化 |
| 10-100 GB | 严重 | 查询极慢(5-10 倍),连锁拖慢整个资源池 |
| > 100 GB | 灾难 | 需要立即处理,可能耗尽磁盘空间 |
2.3 方法三:对比 CPU time 与 Clock time¶
Spill 的典型特征是 CPU 很低但执行时间很长——因为查询在等磁盘 I/O。
SELECT operator_name,
path_id,
SUM(DECODE(counter_name, 'execution time (us)', counter_value, NULL)) AS cpu_time_us,
SUM(DECODE(counter_name, 'clock time (us)', counter_value, NULL)) AS clock_time_us
FROM v_monitor.execution_engine_profiles
WHERE transaction_id = :t_id
AND statement_id = :s_id
AND counter_name IN ('execution time (us)', 'clock time (us)')
GROUP BY operator_name, path_id
ORDER BY cpu_time_us DESC
LIMIT 10;
如果 GroupByHash 或 JoinHash 的 cpu_time / clock_time < 0.3,说明算子大部分时间在等待——极大概率是 Spill 导致的磁盘 I/O。
2.4 方法四:通过 resource_acquisitions 看额外申请频率¶
Spill 往往伴随频繁的 AcquireAdditional 请求——因为原始 query_budget 不够,算子在执行中不断向 Resource Manager 申请更多内存。
SELECT transaction_id, statement_id,
COUNT(*) AS additional_requests,
SUM(memory_inuse_kb) AS total_extra_kb
FROM v_monitor.resource_acquisitions
WHERE request_type = 'AcquireAdditional'
AND transaction_id = :t_id
AND statement_id = :s_id
GROUP BY transaction_id, statement_id;
如果 additional_requests > 5 且 total_extra_kb > query_budget,说明查询的初始预算严重不足。
3. query_budget 与 Spill 的关系¶
3.1 query_budget 的本质¶
query_budget 是优化器为每条查询分配的「初始内存预算」。它决定了优化器生成执行计划时的内存假设:
优化器看到预算后,会评估每个算子需要多少内存,并决定:
- 使用
GroupByHash(需要内存中的哈希表)还是GroupByPipe(流式,不需要哈希表) - 将 JOIN 的内表加载到内存(Hash Join)还是排序后归并(Merge Join)
- 分配多少内存给排序缓冲区
如果 query_budget 太小,优化器可能在明知内存不够的情况下,仍然被迫选择 Hash 类算子——因为排序投影不存在,Pipe 类算子不可用。
3.2 query_budget vs MAXMEMORYSIZE¶
这两个参数经常被混淆,区别如下:
| 参数 | 作用域 | 关系 |
|---|---|---|
MAXMEMORYSIZE |
池级别——池中所有查询总共能用的内存 | 池的总上限 |
query_budget |
查询级别——每条查询的初始预算 | = [MAX]MEMORYSIZE / PLANNEDCONCURRENCY(只读) |
典型误区:管理员看到 query_budget_kb 太小,试图直接设置它。但 query_budget 是计算列,无法直接修改。正确的方式是调整 [MAX]MEMORYSIZE 或 PLANNEDCONCURRENCY。
3.3 多大的 query_budget 才够?¶
这取决于查询的数据量和复杂度。一般经验:
| 查询类型 | 处理数据量 | 推荐 query_budget | 说明 |
|---|---|---|---|
| 简单聚合(< 10 列,< 5 个 GROUP BY) | < 1 亿行 | 2-4 GB | 哈希表通常能在 2GB 内完成 |
| 中等聚合(含多维钻取) | 1-10 亿行 | 4-8 GB | 多维度导致哈希表膨胀 |
| 大型 JOIN + 聚合 | 10-100 亿行 | 8-20 GB | JOIN 内表加载需要额外内存 |
| 超大 ETL / 全量扫描 | > 100 亿行 | 20-50 GB | 考虑分批复用预聚合,而非单次全量 |
验证方法:用 PROFILE 执行高频查询,查看 cumulative size of raw temp data。如果为 0,说明当前 query_budget 足够;如果有值,用该值反推需要多大预算。
3.4 Spill 的连锁反应模型¶
Spill 不只是让一条查询变慢,它会触发连锁反应:
单条查询 Spill ──→ 查询执行时间变长
──→ 长时间占用资源池内存和 MAXCONCURRENCY 名额
──→ 其他查询排队等待
──→ 排队查询堆积
──→ 总并发内存占用上升
──→ 更多查询的 query_budget 不足
──→ 更多 Spill + RESOURCE_REJECTED
这就是为什么有时集群看起来「莫名其妙就慢了」——一条 Spill 查询可以在 10 分钟内拖垮整个资源池。
4. 解决 Spill:三种途径¶
4.1 途径一:增大内存预算(最快,立即生效)¶
直接增大 query_budget 让 GroupByHash 和 JoinHash 有足够的内存避免溢出。
操作方式:
-- 方案 A:降低 PLANNEDCONCURRENCY,增大每条查询的预算
-- 节点 256GB,目标预算 8GB:256 × 95% / 30 ≈ 8.1 GB
ALTER RESOURCE POOL general PLANNEDCONCURRENCY 30;
-- 方案 B:为报表查询创建大预算专用池
-- query_budget = 512GB × 30% / 6 ≈ 25 GB
CREATE RESOURCE POOL heavy_report_pool
MAXMEMORYSIZE '30%'
PLANNEDCONCURRENCY 6
MAXCONCURRENCY 4;
适用场景:查询无法或不值得改写,硬盘空间充足,增加内存预算能立即见效。
局限:PLANNEDCONCURRENCY 降低意味着并发降低——更多查询排队。需要在「单查询速度」和「整体吞吐量」之间平衡。
4.2 途径二:创建排序投影,让 GroupByPipe 替代 GroupByHash(根本解决)¶
这是消除 GROUP_BY_SPILLED 最彻底的方案。GroupByPipe 是一种流式聚合算子:它假设数据已经按照 GROUP BY 列排好序,因此不需要构建哈希表,直接边读边聚合。
前提条件:投影的 ORDER BY 列与查询的 GROUP BY 列一致。
示例:查询按 region, product_category, date 聚合:
-- 经常跑的聚合查询
SELECT region, product_category, date, SUM(amount)
FROM sales_fact GROUP BY region, product_category, date;
-- 创建排序投影使 GroupByPipe 可用
CREATE PROJECTION sales_grouped
AS SELECT * FROM sales_fact
ORDER BY region, product_category, date
SEGMENTED BY HASH(region) ALL NODES;
创建后,优化器会自动识别排序投影并使用 GroupByPipe,该算子几乎不消耗内存——因为数据已经有序,读完一组就输出一组,不需要哈希表。
GroupByHash vs GroupByPipe 对比:
| 特性 | GroupByHash | GroupByPipe |
|---|---|---|
| 内存需求 | 高(需要完整哈希表) | 极低(流式处理) |
| Spill 风险 | 高 | 不会 Spill |
| CPU 消耗 | 高(哈希计算 + 冲突解决) | 低(仅比较当前行与上一行) |
| 前提条件 | 无 | 需要有按 GROUP BY 列排序的投影 |
| 适用场景 | 临时查询(无匹配投影) | 高频固定模式的聚合查询 |
详见 Vertica 性能调优 - 3 重新设计 PROJECTION。
4.3 途径三:优化查询本身(减少需要处理的数据量)¶
有时候 Spill 不是内存太小,而是查询处理了太多不必要的数据。
子策略 3a:添加 WHERE 谓词 + 分区裁剪
-- 没有分区的表,全表扫描
SELECT region, SUM(amount)
FROM sales_fact GROUP BY region; -- 扫描所有 100 亿行 → 必然 Spill
-- 加上分区键过滤,只扫描需要的分区
ALTER TABLE sales_fact PARTITION BY date;
SELECT region, SUM(amount)
FROM sales_fact
WHERE date BETWEEN '2026-05-01' AND '2026-05-28'
GROUP BY region; -- 只扫描 28 天数据 → 可能无需 Spill
子策略 3b:减少 GROUP BY 列数
每多一个 GROUP BY 列,哈希表的键就多一维,内存消耗指数增长。如果业务上不需要某个分组维度,去掉它:
-- 6 个 GROUP BY 列,哈希表极大
SELECT region, province, city, category, subcategory, date, SUM(amount)
FROM sales GROUP BY 1,2,3,4,5,6;
-- 按需减少到 3 个,哈希表缩小 10 倍以上
SELECT region, category, date, SUM(amount)
FROM sales GROUP BY region, category, date;
子策略 3c:子查询预聚合 + 小表 JOIN
对于「先 JOIN 大表再聚合」的场景,改为「先聚合小粒度再 JOIN」:
-- 原始:大表 JOIN 后再聚合 → JoinHash 内表加载全部数据
SELECT d.category, SUM(f.amount)
FROM fact f JOIN dim d ON f.product_id = d.product_id
GROUP BY d.category;
-- 优化:先聚合 fact,缩小后再 JOIN → JoinHash 内表只有几百行
WITH pre_agg AS (
SELECT product_id, SUM(amount) AS total
FROM fact GROUP BY product_id
)
SELECT d.category, SUM(p.total)
FROM pre_agg p JOIN dim d ON p.product_id = d.product_id
GROUP BY d.category;
4.4 三种途径选择指南¶
查询有 Spill 事件
│
├─ 有排序投影匹配 GROUP BY 列?
│ ├─ 是 → 4.2 创建排序投影(首选,根治)
│ └─ 否 → 进入下一步
│
├─ 查询能否优化(缩小数据量)?
│ ├─ 是 → 4.3 优化查询(加 WHERE、减 GROUP BY、子查询预聚合)
│ └─ 否 → 进入下一步
│
└─ → 4.1 增大 query_budget(次选,治标)
└─ 同时设置 MAXCONCURRENCY 防止并发过高反噬内存
5. 深入案例¶
5.1 虚构案例一:hash join spill 导致批处理任务超时¶
📝 虚构案例
场景:ETL 任务每天凌晨 2 点执行,对 5 亿行的 orders 和 2 亿行的 order_details 做 JOIN 后聚合。任务近期从 15 分钟恶化到 2 小时,导致下游报表无法按时刷新。
诊断:
Step 1: PROFILE 执行 ETL SQL
→ JOIN_SPILLED 事件 × 8 个节点
→ cumulative size of raw temp data = 85 GB
Step 2: 查看 query_budget
→ etl_pool: query_budget = 3 GB(MAXMEMORYSIZE 40% / PLANNEDCONCURRENCY 24)
Step 3: 查看 execution_engine_profiles
→ JoinHash 算子: memory_reserved = 3 GB, spill = 82 GB
→ 内表 order_details 有 2 亿行,加载到内存构建哈希表需要约 15GB
→ 3 GB 预算只有需求的 20%
根因:优化器根据统计信息估算内表大小,但统计信息已过期(最后更新是 3 个月前),实际数据增长了 3 倍。
修复:
- 更新统计信息:
SELECT ANALYZE_STATISTICS('order_details'); - 降低
PLANNEDCONCURRENCY增大query_budget:ALTER RESOURCE POOL etl_pool PLANNEDCONCURRENCY 8; - 为
order_details的 JOIN 键创建排序投影,使 JoinMerge 可用
效果:query_budget 从 3GB → 9GB,Spill 从 85GB → 0,ETL 从 2 小时恢复至 12 分钟。
5.2 虚构案例二:用 GroupByPipe 根除 Spill¶
📝 虚构案例
场景:BI 看板每小时刷新一次,核心查询对 sales_fact(30 亿行)做 GROUP BY region, product_category, date 聚合。每次执行都有 GROUP_BY_SPILLED,spill 约 12GB,耗时 4 分钟。
诊断:查看当前投影:
SELECT projection_name, is_super_projection, segment_expression
FROM v_catalog.projections
WHERE anchor_table_name = 'sales_fact' AND is_super_projection = 't';
→ 只有 super projection,ORDER BY 是随机列,无法使用 GroupByPipe。
修复:
CREATE PROJECTION sales_bi_proj
AS SELECT * FROM sales_fact
ORDER BY region, product_category, date
SEGMENTED BY HASH(region) ALL NODES;
SELECT start_refresh(); -- 刷新投影数据
效果:
- 优化器自动选择
sales_bi_proj,使用GroupByPipe代替GroupByHash GROUP_BY_SPILLED消失- 执行时间从 4 分钟 → 30 秒(8 倍提升)
- 内存消耗从 12GB → 800MB
关键:创建投影后一定要跑
start_refresh()让数据物理写入新投影。没有数据的投影不会被优化器选用。
5.3 真实案例:统计信息过期 + query_budget 过小双重放大¶
📋 真实案例
背景:某运营商经分系统,138 节点集群。高峰期 app_pool 大量排队,性能恶化超过 7 倍。
关键发现(详见 Vertica 内存压力诊断与调优 案例 5.3):
app_pool的query_budget = 1 GB,但 40% 的查询实际内存消耗 > 1GB- 某条大查询因
user_dtal表统计信息过期,14.5 亿行表被错误选为 JOIN 内表,JoinHash 构建消耗 28GB 内存 - 统计信息过期导致优化器低估内存需求 → query_budget 不足 → AcquireAdditional 频繁 → 高峰期排队加剧 → 连锁 Spill
这个案例完美展示了 Spill 的双重放大效应:统计信息不准 → 预算低估 → 实际内存远超预留 → Spill + 额外申请 → 连锁反应。
6. 完整诊断流程实战¶
📝 虚构场景 · 完整演练
场景¶
- 4 节点集群(每节点 512GB/64 核),general 池默认配置
- BI 团队反馈:某个看板查询上周还能 10 秒完成,本周突然要 90 秒
- SQL 没有任何修改,数据量增加约 20%
诊断过程¶
Step 1:PROFILE 确认是否有 Spill
→ GROUP_BY_SPILLED × 1,cumulative size of raw temp data = 18 GB
Step 2:量化 Spill 严重度
→ 18GB spill 属于「严重」级别,查询执行时间 90 秒中约 60 秒花在 GroupByHash 的磁盘 I/O 上
Step 3:查看 query_budget
SELECT pool_name, query_budget_kb
FROM v_monitor.resource_pool_status
WHERE node_name ILIKE '%0001%' AND pool_name = 'general';
→ query_budget = 5.1 GB(512 × 95% / 64 = 7.6GB?不对...)
等等,512GB × 95% / 64 = 7.6 GB。实际只有 5.1 GB,说明管理员之前调整过。
Step 4:查看是否有排序投影可用
SELECT projection_name, sort_position, projection_column_name
FROM v_catalog.projection_columns
WHERE anchor_table_name = 'sales_fact'
AND sort_position >= 0
ORDER BY projection_name, sort_position;
→ sales_fact_super 投影的 ORDER BY 是 date_key, product_key, store_key,而查询的 GROUP BY 是 region, category, date——完全不匹配,无法使用 GroupByPipe。
Step 5:分析数据量变化
上周数据量:约 8 亿行 → 本周数据量:约 9.6 亿行(增长 20%)。GroupByHash 的哈希表从约 4 GB 增长到约 6.5 GB,超过了 query_budget = 5.1 GB 的阈值。这就是超过临界点的「最后一根稻草」。
修复¶
- 创建排序投影(根本解决):
CREATE PROJECTION sales_dashboard_proj
AS SELECT region, category, date, amount
FROM sales_fact
ORDER BY region, category, date
SEGMENTED BY HASH(region) ALL NODES;
SELECT start_refresh();
- 短期兜底(增大 query_budget 到 10GB):
效果:排序投影刷新后,查询从 90 秒 → 8 秒,Spill = 0。
7. 快速诊断 SQL 工具箱¶
| 诊断目标 | SQL |
|---|---|
| 检测 Spill 事件 | SELECT event_type, operator_name, suggested_action FROM query_events WHERE transaction_id=:t_id AND statement_id=:s_id AND event_type IN ('GROUP_BY_SPILLED','JOIN_SPILLED'); |
| 量化 Spill 大小 | SELECT operator_name, path_id, SUM(DECODE(counter_name,'cumulative size of raw temp data (bytes)',counter_value,NULL)) AS spill_bytes FROM execution_engine_profiles WHERE transaction_id=:t_id AND statement_id=:s_id GROUP BY 1,2 HAVING SUM(DECODE(counter_name,'cumulative size of raw temp data (bytes)',counter_value,NULL))>0 ORDER BY 3 DESC; |
| 查询预算检查 | SELECT pool_name, query_budget_kb, max_memory_size_kb, planned_concurrency FROM resource_pool_status WHERE pool_name NOT IN ('sysquery','sysdata') AND node_name ILIKE '%0001%'; |
| GroupByHash vs Pipe 确认 | SELECT operator_name, path_id, SUM(counter_value) FROM execution_engine_profiles WHERE transaction_id=:t_id AND statement_id=:s_id AND operator_name IN ('GroupByHash','GroupByPipe') AND counter_name ILIKE 'execution%' GROUP BY 1,2; |
| CPU/Clock 比值 | SELECT operator_name, SUM(DECODE(counter_name,'execution time (us)',counter_value,NULL))/NULLIF(SUM(DECODE(counter_name,'clock time (us)',counter_value,NULL)),0)::FLOAT FROM execution_engine_profiles WHERE transaction_id=:t_id AND statement_id=:s_id GROUP BY 1 ORDER BY 2; |
| 额外内存申请 | SELECT transaction_id, statement_id, COUNT(*), SUM(memory_inuse_kb) FROM resource_acquisitions WHERE request_type='AcquireAdditional' AND transaction_id=:t_id AND statement_id=:s_id GROUP BY 1,2; |
| 排序投影存在性 | SELECT projection_name, sort_position, projection_column_name FROM projection_columns WHERE anchor_table_name='<table>' AND sort_position>=0 ORDER BY 1,2; |
| 统计信息状态 | SELECT projection_name, projection_column_name, statistics_type, statistics_updated_timestamp FROM projection_columns WHERE table_name='<table>' AND sort_position>=0 ORDER BY 1,2; |
8. 最佳实践清单¶
- PROFILE 高频查询检查 Spill:每个重要的 SQL 至少用
PROFILE跑一次,确认没有GROUP_BY_SPILLED或JOIN_SPILLED。这是性能基线的必要步骤。 - 排序投影是根治 Spill 的第一选择:
GroupByPipe不需要哈希表,理论上永远不 Spill。为高频聚合查询创建匹配的排序投影,投入产出比极高。 - query_budget 设到「够用」而非「刚好」:数据会增长。如果现在的查询刚好不 Spill(spill_bytes ≈ 0),给 query_budget 留 30-50% 余量。
- 统计信息必须准确:过期统计信息是 Spill 的隐形推手。每次大批量加载后运行
ANALYZE_STATISTICS,让优化器能看到真实数据规模。 - 分区 + WHERE 是减少数据量的最简单方法:如果表有 3 年数据但每次只查 1 个月,分区裁剪能减少 90% 以上的 SCAN 数据,间接消除 Spill。
- Spill > 10GB 必须干预:不要等查询慢到用户投诉才处理。设置监控,
cumulative size of raw temp data > 10GB触发告警。 - 大 JOIN 场景优先考虑预连接投影:运行时 JOIN 需要加载整个内表到内存。预连接投影在加载数据时就完成 JOIN,查询时直接读取结果——零 Spill。
- 利用子查询预聚合缩小 JOIN 数据量:先用 GROUP BY 在子查询中大幅压缩数据,再与维度表 JOIN。小表 JOIN 几乎不会 Spill。
- 不要一个池管所有:将 ETL、BI 报表、ad-hoc 查询分到不同资源池,各自有独立的
query_budget。一条大查询在专用池里 Spill,不影响其他池。 - Data growth 是 Spill 的头号敌人:数据增长 20% 就可能让原本不 Spill 的查询越过临界点。容量规划时应周期性 PROFILE 关键查询,确认 Spill 余量。
扩展阅读¶
- Vertica 错误日志解读与常见错误处理 — 错误日志中 Spill 相关信号的识别与监控
- Vertica 内存压力诊断与调优 — Spill 的根本原因是内存不足
- Vertica CPU 持续高负载诊断与优化 — Spill 导致磁盘 I/O,CPU 反而空闲
- Vertica 资源池最佳实践 — query_budget 与资源池参数详解
- Vertica 性能调优 - 3 重新设计 PROJECTION — 排序投影让 GroupByPipe 替代 GroupByHash
- Vertica 统计信息管理与查询性能 — 统计信息缺失是 Spill 的重要根因