立即咨询
2026.07.14 |
OB优化案例:一条SQL竟生成了10T临时文件
OceanBase 集群某节点 3 小时内磁盘从 6T 飙到 17T,根因竟是一条 SELECT 生成了约 10T 临时文件。本文完整复盘新浦金350vip有限公司东区技术团队的排查链路(observer 日志 → TOP-SQL → ASH 视图 → SQL 逻辑分析),并给出临时文件上限的规范化设置建议。

一、故障现象:毫无征兆的磁盘危机

某日,我们的 OceanBase 集群某节点毫无征兆地爆发磁盘危机——短短 3 小时内,该节点磁盘占用从 6T 一路飙到 17T。没有任何前期征兆,也没有批量数据导入之类的"常规嫌疑人",空间就像被一只看不见的手迅速掏空。

这种"凭空消失"的磁盘空间,第一时间让我们把目光投向了临时文件:在 OceanBase 中,临时文件类似于 Oracle 的临时表空间,用于存放 HASH 计算、排序等算子的中间数据。当 SQL 执行产生大量中间结果时,临时文件会迅速膨胀。


二、排查过程

1 步:分析 observer 日志

我们用关键字 mark_and_sweep 过滤 observer 日志。该关键字会周期性打印磁盘使用情况,是定位"空间被谁吃了"的第一现场。

14:05:36 的日志中,我们看到这样一行关键数据:

tmp_file_count=4790388

这是临时文件的宏块数。OceanBase 中每个宏块为 2M,因此:

4790388 × 2M ≈ 9356G ≈ 9.14T

数字对上了——磁盘空间的膨胀,正是来自临时文件的疯狂写入。

2 步:查看 TOP-SQL

回到问题时段,我们在 OCP 的 TOP-SQL 中发现了一条异常 SQL:它的执行耗时高达 3 小时,与"数据膨胀到报错"的时长完全吻合。时间线对上了,嫌疑 SQL 锁定。

3 步:分析 ASH 视图

为了看清这条 SQL 慢在哪里,我们查询了 ASH(Active Session History)视图:

select sql_id, trace_id, sql_plan_line_id, count(*) * 10 cnt
from dba_wr_active_session_history
where sql_id = 'A77650731411859E9886898E9122759D'
group by sql_id, trace_id, sql_plan_line_id
order by sql_id, trace_id, cnt;

结果显示,这条 SQL 主要消耗在执行计划的 0 步——也就是最底层的扫描/关联阶段。问题不在某个深层算子,而在一开始的数据膨胀。

4 步:剖析问题 SQL 文本

问题 SQL 的核心逻辑如下(已脱敏):

WITH T2 AS (
  SELECT col1 as col1id, CURRENTSTEPSEQ, SGESTEPSEQ, TXNTIME
  FROM (
    SELECT col1, CURRENTSTEPSEQ, SGESTEPSEQ, TXNTIME,
           ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY TXNTIME DESC) as rn
    FROM T1
    WHERE col1 = 'xxxxxx'
      AND TXNTIME BETWEEN '20260519160000' AND '20260520120000'
  )
  WHERE rn = 1 AND CURRENTSTEPSEQ IS NOT NULL AND SGESTEPSEQ IS NOT NULL
),
step_positions AS (
  SELECT STEPSEQ, ROW_NUMBER() OVER(ORDER BY STEPSEQ) as step_row_num
  FROM T3
  WHERE STEPSEQ IN (SELECT CURRENTSTEPSEQ FROM T2 UNION SELECT SGESTEPSEQ FROM T2)
)
SELECT a.col1id, a.CURRENTSTEPSEQ, a.SGESTEPSEQ, a.TXNTIME,
       cs.step_row_num as current_step_row,
       ss.step_row_num as sge_step_row,
       -(ss.step_row_num - cs.step_row_num) as THEORETICAL_VALUE
FROM T2 a
JOIN step_positions cs ON cs.STEPSEQ = a.CURRENTSTEPSEQ
JOIN step_positions ss ON ss.STEPSEQ = a.SGESTEPSEQ;

5 步:分析 SQL 逻辑——近乎笛卡尔积的膨胀

问题的根源在最后一段:step_positions 这个派生表被关联了两次(分别与 CURRENTSTEPSEQSGESTEPSEQ JOIN)。而 STEPSEQ 字段对应的行数越多,返回行数就呈2 次方膨胀。

· 测试取 30000 行,最终返回约 10 亿行(近笛卡尔积效果);

· STEPSEQ 取值最多的记录高达 200 万行

· 若实际取到 50 万行记录,最终将返回约 2500 亿行

一条本应返回少量结果的查询,因表被反复关联,瞬间放大成天文数字,临时文件随之被写到约 10T。

6 步:OceanBase 临时文件限制机制

为什么能写到 10T 而没提前拦住?这涉及 OB 的临时文件管控机制:

· V4.2 及之前:临时文件上限采用固定算法,基本可达约 100T,等于"无限制";

· V4.3 / V4.4:改为由参数 temporary_file_max_disk_size 控制总大小,但默认值 0,同样等于无限制

也就是说,产研把"设不设限、设多少"的选择权交给了使用者——默认情况下,临时文件可以一路狂奔到把磁盘写满。


三、总结建议

根因:问题 SQL 存在逻辑缺陷(同一张派生表被多次关联,产生近笛卡尔积效果),在 3 小时内生成约 10T 临时文件;同时 OceanBase V4.3/V4.4 虽有参数可控,但默认无限制。

运维建议

1. 规范参数V4.3+ 环境建议将 temporary_file_max_disk_size 纳入规范参数模板,并按业务类型设值,避免空间暴增;

2. 预留空间:为临时文件长期预留独立空间,防止波及数据盘;

3. 排查三步法(详见下方):

· ① 日志:grep mark_and_sweep observer.log 看磁盘使用;

· ② 视图:select sum(data_bytes/1024/1024) from dba_ob_temp_files;

· ③ 设限:alter system set temporary_file_max_disk_size = '2T';


关于新浦金350vip有限公司

北京新浦金350vip安图科技股份有限公司(简称"新浦金350vip有限公司",股票代码 301208)是国内领先的第三方 IT 基础架构服务与产品提供商。公司具备全栈服务能力,可为全周期、全行业的客户提供数据库运维、性能优化、故障排查等全方位服务。数据库运维是公司最具技术含量的优势项之一,但公司的能力远不止于此——全栈、全周期、全行业,才是新浦金350vip有限公司的底色。

相关推荐
助力IT企业信创服务,和企业一起走向成功
立即领取企业福利 预约您的专属顾问
400-008-1713
XML 地图