执行 ALTER TABLE "xxx" MODIFY "xxxxtime" DATETIME(6);SQL 错误 [4013] [HY001]: No memory or reach tenant memory limit

【 使用环境 】POC 验证环境
【 OB or 其他组件 】OBServer
【 使用版本 】5.7.25-OceanBase_CE-v4.3.5.1
【问题描述】更新一个接近300万行表的字段类型 从 DATETIME 到 DATETIME(6)
ALTER TABLE “xxx” MODIFY “xxxxtime” DATETIME(6)
DBeaver前端报错
org.jkiss.dbeaver.model.sql.DBSQLException: SQL 错误 [4013] [HY001]: No memory or reach tenant memory limit

alert日志如下图

observer.log

【复现路径】问题出现前后相关操作
【附件及日志】推荐使用OceanBase敏捷诊断工具obdiag收集诊断信息,详情参见链接(右键跳转查看):

【SOP系列 22 】——故障诊断第一步(自助诊断和诊断信息收集)

【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手] 即可召唤小助手,欢迎试用!

根因分析场景: DDL过程中报磁盘空间不足的问题
根因分析命令: obdiag rca run --scene=ddl_disk_full
日志采集场景: 内存问题
日志采集命令: obdiag gather scene run --scene=observer.memory

为了更好地帮助您解决此问题,建议您使用上述命令进行根因分析和日志采集,并将采集到的日志提供给我们以便确认问题所在。以下是进一步需要了解的信息:

  1. 您的租户内存限制(tenant memory limit)是多少?是否可以适当调整以满足当前操作的需求?
  2. 在执行 ALTER TABLE 操作之前,是否有其他高内存消耗的操作正在运行?例如大规模数据导入或复杂查询?
  3. 您能否提供具体的 SQL 语句以及涉及的表结构信息?这有助于我们更准确地评估内存需求。
  4. 当前系统中是否存在其他同时运行的 DDL 或者长时间运行的任务,可能会占用较多资源?
  5. 您的 OceanBase 数据库版本是什么?不同版本可能对内存管理有不同的优化策略。

附上敏捷诊断工具 obdiag 使用帮助链接

查询下 变量 ob_sql_work_area_percentage 大小如果是5的话调到10在执行alter看看。

obclient(root@dsp_tt)[oceanbase]> select * from GV$OB_MEMSTORE limit 1\G
*************************** 1. row ***************************
SVR_IP: 10.xx.xx.2
SVR_PORT: 2882
TENANT_ID: 1004
ACTIVE_SPAN: 536870912
FREEZE_TRIGGER: 6721642244
FREEZE_CNT: 0
MEMSTORE_USED: 536870912
MEMSTORE_LIMIT: 30923764500
1 row in set (0.009 sec)

obclient(root@dsp_tt)[oceanbase]> show variables like ‘ob_sql_work_area_percentage’;
±----------------------------±------+
| Variable_name | Value |
±----------------------------±------+
| ob_sql_work_area_percentage | 10 |
±----------------------------±------+
1 row in set (0.005 sec)

obclient(root@dsp_tt)[oceanbase]>

老师您好调整 ob_sql_work_area_percentage=10% 还是有报错,是否可session 级别在调大一些??

报错日志如下

2025-05-27 14:37:49.659897|WARN|USING_LOG_PREFIX|OB_LIB_ALLOCATE_MEMORY_FAIL|-4013|1004|26541|T1004_PX_G0|Y100B420A100B02-00063323734FF84A-0-0|print_alloc_failed_msg|alloc_failed_reason.cpp:141|"[oops]: alloc failed reason is that ctx memory has reached the upper limit(ctx_name: WORK_AREA, ctx_hold: 6184501248, ctx_limit: 6184752900, alloc_size: 2097152)"
2025-05-27 14:39:03.825717|WARN|USING_LOG_PREFIX|OB_LIB_ALLOCATE_MEMORY_FAIL|-4013|1004|26541|T1004_PX_G0|Y200B420A100B02-00063323734FF84A-0-0|print_alloc_failed_msg|alloc_failed_reason.cpp:141|"[oops]: alloc failed reason is that ctx memory has reached the upper limit(ctx_name: WORK_AREA, ctx_hold: 6184501248, ctx_limit: 6184752900, alloc_size: 2097152)"
2025-05-27 14:40:17.870091|WARN|USING_LOG_PREFIX|OB_LIB_ALLOCATE_MEMORY_FAIL|-4013|1004|26541|T1004_PX_G0|Y300B420A100B02-00063323734FF84A-0-0|print_alloc_failed_msg|alloc_failed_reason.cpp:141|"[oops]: alloc failed reason is that ctx memory has reached the upper limit(ctx_name: WORK_AREA, ctx_hold: 6184501248, ctx_limit: 6184752900, alloc_size: 2097152)"

根据您提供的信息,问题的核心是 内存不足,导致 ALTER TABLE 操作失败。以下是详细的分析和解决方案建议:


1. 当前内存使用情况分析

从您提供的 GV$OB_MEMSTORE 查询结果可以看出:

  • MEMSTORE_USED: 当前内存存储已使用量为 536,870,912 字节 (约 512 MB)
  • MEMSTORE_LIMIT: 内存存储限制为 30,923,764,500 字节 (约 28.8 GB)

这表明租户的内存限制较大,但当前内存分配可能已经接近某些特定上下文(如 WORK_AREA)的限制。

此外,ob_sql_work_area_percentage 的值为 10%,这意味着 SQL 执行时的工作区内存限制为租户总内存的 10%。结合日志中的信息:

  • ctx_hold: 当前持有的内存为 6,184,501,248 字节 (约 5.76 GB)
  • ctx_limit: 上下文内存限制为 6,184,752,900 字节 (约 5.76 GB)

这说明 WORK_AREA 的内存已经接近上限,无法再分配更多内存。


2. 解决方案

方法一:调整 ob_sql_work_area_percentage

您可以尝试在会话级别临时调整 ob_sql_work_area_percentage 的值,以增加工作区内存的限制。例如,将其设置为 20% 或更高:

SET SESSION ob_sql_work_area_percentage = 20;

然后重新执行 ALTER TABLE 操作。如果问题仍然存在,可以逐步增加该值,直到操作成功。

注意: 调整此参数可能会对其他正在运行的任务产生影响,请确保租户有足够的剩余内存。


方法二:分批次修改表结构

如果调整内存参数后仍然报错,可以考虑将大表拆分为多个小批次进行修改。具体步骤如下:

  1. 创建一个新表,包含目标字段类型:

    CREATE TABLE new_table AS SELECT * FROM xxx WHERE 1=0;
    ALTER TABLE new_table MODIFY xxxxtime DATETIME(6);
    
  2. 使用 INSERT INTO ... SELECT 分批次插入数据:

    INSERT INTO new_table SELECT * FROM xxx WHERE id BETWEEN start_id AND end_id;
    

    根据表的大小和系统负载,合理划分批次范围。

  3. 删除旧表并重命名新表:

    DROP TABLE xxx;
    RENAME TABLE new_table TO xxx;
    

这种方法可以有效减少单次操作的内存消耗。


方法三:增加租户内存限制

如果上述方法仍无法解决问题,可能是租户的整体内存限制不足。可以通过以下命令增加租户的内存限制:

ALTER RESOURCE UNIT unit_name SET memory_size = '更大值';
ALTER TENANT tenant_name UNIT_CONFIG = unit_name;

请根据实际需求调整 memory_size 的值,并确保服务器有足够的物理内存支持。


3. 其他建议

  • 监控内存使用情况: 在执行 DDL 操作时,实时监控租户的内存使用情况,避免因其他高内存消耗任务导致资源竞争。
  • 优化表结构: 如果表中存在大量冗余数据或不必要的索引,可以先进行清理以减少内存压力。
  • 升级版本: 如果条件允许,建议升级到最新版本的 OceanBase 社区版,以获得更好的性能优化和内存管理能力。

总结

当前问题是由于 WORK_AREA 内存不足导致的。您可以优先尝试 调整 ob_sql_work_area_percentage 参数分批次修改表结构。如果问题仍未解决,可以考虑 增加租户内存限制。同时,建议使用 OceanBase 敏捷诊断工具 obdiag 收集更多日志信息,以便进一步分析问题根源。

如有其他疑问,请随时联系!

更多信息请查看:

  1. 使用命令行进行运维

(小助手的答复已结束,如未能解决您的问题,请继续提问并等待其他同学的回复,谢谢!)

可以调更大,你的租户规格是多大的

老师您好租户规格如下:

再扩点试试顺便获取一下相关日志
1)设置trace信息
SET ob_enable_show_trace=‘ON’;

2)执行sql。

3)获取上个命令的trace
select last_trace_id();

4)获取trace对应的节点
select query_sql,svr_ip from gv$ob_sql_audit where trace_id=‘第三步获取的trace信息’;

5)取对应的svr_ip节点 过滤日志
grep “第三步获取的trace信息” observer.log*
grep “第三步获取的trace信息” rootservice.log*

6)提供日志信息即可。

1 个赞

小助手老师您好:
调整ob_sql_work_area_percentage=20% 该问题得以解决多谢

小助手是AI :rofl:

老师您户
租户级别 global 调整ob_sql_work_area_percentage=20% 该问题得以解决,
想继续问一下,是否应该把该值调回到 5% 或10%,是否可通过相关视图查看租户 ob_sql_work_area 组件占用的内存,来评估一个合理的值,包括其它内存组件常用参数的调整是否有推荐值?

调回去吧。SQL WORK AREA 工作区内存,是指 SQL 排序等阻塞性算子使用的内存,通过租户系统变量 ob_sql_work_area_percentage 控制,默认值为 5%,即 工作区内存 = 租户内存 * ob_sql_work_area_percentage(默认 5%)

如果请求并发量较大,且每个请求占用的工作区内存比较多,可能出现工作区内存不足的报错,经常出现的场景有 unionsortgroup by 等。上述问题如果出现,可以通过适当调大系统变量ob_sql_work_area_percentage来进行规避。
如果频繁出现内存不足问题,建议扩容下租户内存了

1 个赞

原来如此,感谢老师哈