执行UPDATE ...LEFT JOIN SET xxxx=xxx 最终报内存不够的错误

版本:5.7.25-OceanBase_CE-v4.3.5.1
内存配置


报错信息
SQL error [11049] [HY000]: Exceed query memory limit
(mem_limit=9663676400, mem_hold=9667026944), please check whether the query_memory_limit_percentage configuration item is reasonable.

问题描述
示例sql在下方:
通过update left join set的写法对多个值进行更新,但是最终更新的值依赖于上一个同样字段值的结果。其中右表为空,左表有600多行。整个sql大概有2千行左右的更新。同样的sql,mysql可以执行,放到OB上就出错了,是配置的问题还是不支持呢?

UPDATE ht.test_data a LEFT JOIN ht.custom b ON a.kind = b.kind AND a.id = b.id 
SET 
   
    a.product_num = CASE WHEN a.product_time >= (CASE WHEN ISNULL(b.woking_day) = 0 AND LENGTH(trim(b.woking_day)) > 0 THEN b.woking_day ELSE '0900' END) AND a.product_time <= (CASE WHEN ISNULL(b.break_day) = 0 AND LENGTH(trim(b.break_day)) > 0 THEN b.break_day ELSE '1700' END) THEN (CASE WHEN ISNULL(b.product_num1) = 0 AND b.product_num1 > 0 THEN b.product_num1 ELSE '75' END) ELSE (CASE WHEN ISNULL(b.product_num2) = 0 AND b.product_num2 > 0 THEN b.product_num2 ELSE '175' END) END, 
   
    a.product_num = (CASE WHEN a.tminmn > a.product_num THEN a.tminmn ELSE a.product_num END) * a.product_num_tt, 
	
    a.product_num = CASE WHEN (a.product_num > a.product_num_high AND a.product_num_high > 0 AND (a.product_num - a.product_num_high) * 100 / a.product_num_high <= 35) OR (a.product_num < a.product_num_low AND a.product_num_low > 0 AND (a.product_num_low - a.product_num) * 100 / a.product_num_low <= 35) THEN a.product_num + 6 
                    WHEN (a.product_num > a.product_num_high AND a.product_num_high > 0 AND (a.product_num - a.product_num_high) * 100 / a.product_num_high <= 70) OR (a.product_num < a.product_num_low AND a.product_num_low > 0 AND (a.product_num_low - a.product_num) * 100 / a.product_num_low <= 70) THEN a.product_num + 40 
                    ELSE a.product_num + 20 END, 

    a.product_num = a.product_num + (CASE WHEN SUBSTRING(a.kind, 1, 4) IN ('test') THEN 20 ELSE 10 END), 

    a.product_num = CASE WHEN product_time >= (CASE WHEN ISNULL(b.woking_day) = 0 AND LENGTH(trim(b.woking_day)) > 0 THEN b.woking_day ELSE '0900' END) AND product_time <= (CASE WHEN ISNULL(b.break_day) = 0 AND LENGTH(trim(b.break_day)) > 0 THEN b.break_day ELSE '1700' END) AND b.product_num_fix_mn1 IS NOT NULL AND b.product_num_fix_mn1 > 0 THEN b.product_num_fix_mn1 
                    ELSE a.product_num END, 

    a.product_num_flg = CASE WHEN a.product_num_err >= a.product_num AND a.product_num_last_low = 0  THEN 'y' ELSE 'n' END
1 个赞

加大SQL工作内存试试。

1 个赞

配置问题,解析复杂SQL需要分配大量的内存,OB中由租户参数ob_sql_work_area_percentage控制,默认5,小内存租户调整至20,大内存租户调整至10,先这样看下是否可以执行。

1 个赞

目前,我设置的是50,依然是不行的

1 个赞

数据库是单节点还是多节点,租户规格多大?
从报错信息来看:
当前查询的内存限制为 mem_limit=9663676400(约 9.66 GB)。
查询实际占用的内存为 mem_hold=9667026944(约 9.67 GB),超出了限制。 query_memory_limit_percentage这个默认是50,租户内存不够,只能调大参数或者扩容。

1 个赞

单节点部署,租户规格:

又尝试了一些配置:

_min_full_resource_pool_memory=2147483648
memory_chunk_cache_size=0M
memory_limit_percentage=80
system_memory=2G
memory_limit=50G
memory_reserved=500M
query_memory_limit_percentage=50
ob_vector_memory_limit_percentage=0
rpc_memory_limit_percentage=0

ob_sql_work_area_percentage设置为20

查询依然是报错
SQL 错误 [11049] [HY000]: Exceed query memory limit (mem_limit=15461882250, mem_hold=15465766912), please check whether the query_memory_limit_percentage configuration item is reasonable.

15G左右了,貌似是会一直上升的,根据业务场景,这个sql会每30秒执行一次,从执行时间以及内存占用来看貌似不得行。而实际生产环境机器没存也不会那么大。这种情况是否还能从配置解决?还是说目前需要对这个sql本身进行更改?

1 个赞

查一下这个信息
select a.zone,a.svr_ip,b.tenant_name,b.tenant_type, a.max_cpu, a.min_cpu,
round(a.memory_size/1024/1024/1024,2) memory_size_gb,
round(a.log_disk_size/1024/1024/1024,2) log_disk_size,
round(a.log_disk_in_use/1024/1024/1024,2) log_disk_in_use,
round(a.data_disk_in_use/1024/1024/1024,2) data_disk_in_use
from oceanbase.gv$ob_units a join oceanbase.dba_ob_tenants b on a.tenant_id=b.tenant_id order by b.tenant_name;

1 个赞

image

2 个赞

更新报错的时间点的observer.log日志发一下

1 个赞

你这个报错 基本上就是 query_memory_limit_percentage 参数设置的不合理导致的

1 个赞

一般情况下这个值不是越大,内存可使用空间不就越大么,但是表中的总数据也才几百条,与MySQL对比,一个sql的执行占用10几个G,时间也挺长,那当前这个更新方式似乎就不可行了

1 个赞

按照下面的步骤 取一下报错的语句的trace日志
alter system set enable_rich_error_msg=true;
obclient [test]> select count(*) from t2;
ERROR 1146 (42S02): Table ‘test.t2’ doesn’t exist
[xx.xx.xx.1:2882] [2024-04-13 20:10:20.292087] [YB420BA1CC68-000615A0A8EA5E38-0-0]
[root@x.x.x.1 ~]$ grep “YB420BA1CC68-000615A0A8EA5E38-0-0” rootservice.log
[root@x.x.x.1 ~]$ grep “YB420BA1CC68-000615A0A8EA5E38-0-0” observer.log
alter system set enable_rich_error_msg=false;