在 OceanBase 中,当遇到“内存不足”或“租户内存超限”告警时,应该如何进行诊断和调优?

怎么定位消耗内存最大的 SQL、会话或模块,以及常见的解决手段。​

3 个赞

遇事不决,先走一下诊断工具obdiag的巡检,https://www.oceanbase.com/docs/common-obdiag-cn-1000000003892414

1 个赞

OceanBase 内存不足与租户内存超限:诊断与调优指南

当 OceanBase 数据库出现“内存不足”或“租户内存超限”告警时,需系统化地从告警类型识别 → 内存分布分析 → 高消耗 SQL/会话定位 → 调优手段实施四个层面进行排查与优化。

一、常见内存问题及初步诊断

根据 产品 FAQ → 内存 FAQ 的描述,常见的内存异常包括:

问题类型 错误码/报错信息 原因分析
工作区内存不足 ORA-04036: PGA memory used by the instance exceeds PGA_AGGREGATE_LIMIT 或类似提示 工作区(Work Area)内存受限于 租户内存 × ob_sql_work_area_percentage(默认5%),在执行 SORT, GROUP BY, UNION 等操作时易触发
租户内存超限 客户端报错 "Over tenant memory limits",错误码 4013 租户整体内存使用达到上限,可能是某模块(mod)持续增长导致
MemStore 内存耗尽 错误码 4030 写入速度 > 转储速度,导致 MemStore 满,无法接受新写入
OBServer 节点内存超限 日志中出现 server memory has reached the upper limit 整体节点内存配置不合理或存在内存泄漏

:mag: 日志关键词快速定位

  • ctx memory has reached upper limit:上下文内存超限
  • tenant memory has reached the upper limit:租户内存超限
  • server memory has reached the upper limit:服务器总内存超限
  • physical memory exhausted:物理内存不足

来源:产品 FAQ → 内存 FAQ → OceanBase 数据库进行一次内存分配会检查哪些限制?

– 查询所有节点的内存使用情况,按大小降序排列 SELECT SVR_IP, MOD, SUM(HOLD) AS total_hold, SUM(USED) AS total_used FROM GV$OB_MEMORY WHERE TENANT_ID = <your_tenant_id> GROUP BY SVR_IP, MOD ORDER BY total_used DESC;

2. 定位高内存消耗的 SQL 语句

OceanBase 提供了兼容 Oracle 的性能视图,可通过以下方式查找内存消耗高的 SQL:

使用 GV$OB_SQLSTAT 视图(推荐)

此视图记录了 SQL 的运行统计信息,包含内存使用字段。

-- 查找当前租户中平均工作区内存最高的前10条 SQL
SELECT 
    SQL_ID,
    SQL_TEXT,
    AVG_MEM_USED,
    MAX_MEM_USED,
    EXECUTIONS,
    ELAPSED_TIME / EXECUTIONS AS avg_time_us
FROM GV$OB_SQLSTAT 
WHERE TENANT_ID = <your_tenant_id>
  AND LAST_ACTIVE_TIME > SYSDATE - 1/24 -- 近1小时活跃
ORDER BY MAX_MEM_USED DESC 
LIMIT 10;

:warning: 注意:若 SQL 被频繁执行且每次使用大量内存(如大表 JOIN、排序),即使单次未溢出,累积也可能导致租户内存超限。

– 查看当前会话及其执行的 SQL 和等待事件 SELECT SID, SESSION_ID, SQL_ID, CLIENT_IP, CONNECT_TIME, LAST_ACTIVE_TIME FROM GV$SESSION WHERE TENANT_ID = <your_tenant_id> AND STATUS = ‘ACTIVE’;

三、常见调优手段

1. 调整工作区内存比例

对于频繁执行复杂查询的场景,可适当提升 ob_sql_work_area_percentage

-- 设置全局参数(建议逐步调整,避免过度分配)
ALTER SYSTEM SET ob_sql_work_area_percentage = 10 TENANT = <tenant_name>;

:pushpin: 默认值为 5%,最大不超过 90%。调整后需观察整体内存使用趋势,防止其他模块内存被挤压。

来源:产品 FAQ → 内存 FAQ]

2. 优化高内存 SQL

针对定位到的高内存 SQL,采取以下措施:

  • 添加索引:减少全表扫描,降低数据处理量
  • 拆分大查询:将大结果集的 GROUP BYJOIN 拆分为分批处理
  • 启用落盘机制:确保 work_area 支持 spilling(默认开启),避免内存溢出直接失败
  • 使用 Hint 控制执行计划:例如指定 join 方式为 MERGE JOINNESTED LOOP 以降低内存需求

3. 检查并优化 MemStore 行为

如果 GV$OB_MEMSTORE 显示 MemStore 使用过高:

SELECT * FROM GV$OB_MEMSTORE WHERE TENANT_ID = <your_tenant_id>;

可考虑:

  • 增加转储线程数:alter system set minor_freeze_times = 10;
  • 手动触发转储:alter system minor freeze tenant = <tenant_name>;
  • 调整 memstore_limit_percentage 防止单租户占满共享资源
3 个赞