问题描述

问题单

使用GROUP_CONCAT函数时,数据库swap表空间上涨厉害

测试用例
drop table tmp1;
create table tmp1(c1 int,c2 double,c3 varchar(500),c4 int);
 
begin
for i in 1 .. 4994196 loop
insert into tmp1 select random()*100000000,random()*5000000,'hello world test xxxxxiio','' from dual;
end loop;
commit;
end;
/
 
select c1,c2,LISTAGG(c3) value_list from tmp1 where c4 is null group by c1,c2 having to_char(LISTAGG(c3)) = '15395169080,15395169080';
-- 能出结果,(swap空间590M)
 
源表数据2百多M,这个group_concat sql使用1百多G swap空间还不够
select c1,c2,group_concat(c3) value_list from tmp1 where c4 is null group by c1,c2 having to_char(group_concat(c3)) = '15395169080,15395169080';
-- 出不来结果,swap空间越来越大,(直到128.063G,报错退出)
YAS-02025 no free space in virtual memory pool
 
select c1,c2,group_concat(c3) value_list from tmp1 where c4 is null group by c1,c2 ;
-- 能出结果,swap空间一直增大(直到33.188G,报错退出)
YAS-00103 no free block in application pool
 
select c1,c2,group_concat(c3) value_list from tmp1 group by c1,c2
-- 能出结果,swap空间一直增大(直到33.188G,报错退出)
YAS-00103 no free block in application pool
 
select c1,c2 from tmp1 group by c1,c2 ;
-- 能出结果,swap空间到一定大小停下(128M)4994196行
 
select group_concat(c3) value_list from tmp1 ;
-- 能出结果,swap空间一定大小停下(252M)
 
select * from (
select c1,c2,group_concat(c3) value_list from tmp1 where C4 is null group by c1,c2
) where to_char(value_list) = '15395169080,15395169080';
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
结论
  • 23.2版本尝试该问题,现象相同。
  • 确认内置函数group_concat,该函数返回lob类型,导致vm大量增长。该接口需要优化。

规避方法

可以使用listagg替换group_concat。但是如果超过8000个字节,文本会被截断。

分析代码发现,group_concat返回的是lob类型,每一个分组都会申请一个lob空间,每一个lob空间都是88K大小,测试例子有4994196分组,所以它就会申请49941968*8K大小空vm空间,大概是304.8G大小,才能跑完,导致的问题。

代码分析如下

group_concat申请VM空间流程

调用流程

【YashanDB知识库】swap空间使用超大报错_测试用例

group_concat

group_concat返回lob类型,每一个分组都会申请一个lob空间

string转lob时,tmpVar是源表字段数据,调用anlLobAppend给value->vLob申请lob对象空间

【YashanDB知识库】swap空间使用超大报错_表数据_02

【YashanDB知识库】swap空间使用超大报错_测试用例_03

【YashanDB知识库】swap空间使用超大报错_测试用例_04

VM空间申请

调用流程

vmAllocAndOpen
doVmAlloc
vmAllocSwap
vmAllocExtend
spcAllocExtent
doAllocExt
spcAllocDataFileExt
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

【YashanDB知识库】swap空间使用超大报错_崖山数据库_05

申请空间:

【YashanDB知识库】swap空间使用超大报错_函数返回_06

如上unitBlocks = 8,申请8个块的空间

【YashanDB知识库】swap空间使用超大报错_YashanDB_07

如下:4是swap的表文件id

【YashanDB知识库】swap空间使用超大报错_崖山数据库_08

【YashanDB知识库】swap空间使用超大报错_函数返回_09

VM空间扩展

调用流程

spcAllocExtent
doExtendExt
spcExtendDatafile
dfExtend
dbExtendDevice
dbBuildDeviceBlocks
writeDevice
writeFile
write
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

一次扩大,写64M空间,8192*8192

【YashanDB知识库】swap空间使用超大报错_YashanDB_10

【YashanDB知识库】swap空间使用超大报错_测试用例_11

【YashanDB知识库】swap空间使用超大报错_YashanDB_12