暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

ORA-1652: unable to extend temp segment by 128 in tablespace导致流复制中断影响数据同步问题分析

原创 尚雷 2022-11-22
5423

目前两套生产环境采用Oracle流复制进行数据同步,近期因为临时表空间问题导致流复制中断影响数据同步,以下是问题分析和处理过程。

一、 问题描述

前段时间,自一个生产业务用迁移到本地OSS点后,每隔几天就会在晚上21点左右,就会收到本地OSS点流复制捕获进程中断的告警短信。登陆服务器查看数据库告警日志,基本上都是由于如下临时表空间不足导致的。
image.png
根据alert告警日志显示,数据库在某一时刻报 ORA-1652: unable to extend temp segment by 128 in tablespace,提示临时表空间不足,随着时间推移,临时表空间持续被大量占用,最终导致流复制无法使用临时表空间而将捕获器进程宕。

这套数据库,是三节点RAC数据库,数据库版本是Oracle 11.2.0.4,补丁也都打了。三节点上的所有用户共用一个临时表空间,前期已为该临时表空间分配了200G以上空间,在报临时表空间不足时,为其又进行了扩容,并将其扩容到了300G,但隔了没多久又出现此情况。

二、 分析过程

查询临时表空间使用率,如下,显示。
image.png
临时表空间用来管理数据库排序操作以及用于存储临时表、中间排序结果等临时对象,当ORACLE里需要用到SORT的时候,并且当PGA中sort_area_size大小不够时,将会把数据放入临时表空间里进行排序。像数据库中一些操作: CREATE INDEX、 ANALYZE、SELECT DISTINCT、ORDER BY、GROUP BY、 UNION ALL、 INTERSECT、MINUS、SORT-MERGE JOINS、HASH JOIN等都可能会用到临时表空间。当操作完成后,系统会自动清理临时表空间中的临时对象,自动释放临时段。这里的释放只是标记为空闲、可以重用。

然后查询问题发生时段占用临时表空间的SQL如下:
image.png
可以看到该SQL单次执行时占用60多G临时表空间,如果很多应用同时执行,就会把临时表空间耗尽。
image.png
另外可以看到占用临时表空间的临时段的类型都是LOB_DATA和LOB_INDEX类型,对相关的SQL语句进行分析,相关SQL语句如下:
# SQL 已脱敏

SELECT TO_CHAR (WMSYS.WM_CONCAT (a.account_id))
  FROM CRM_ACC a, OSS_ADM_U c
 WHERE     a.owner_id = user_id
       AND PROPERTY = '1'
       AND ADD_MONTHS (SYSDATE, -24) >= A.MOD_TIME
       AND HOMEPAGE IS NULL
       AND NOT EXISTS
                  (SELECT 1
                     FROM SUP_CONT_PERSON S
                    WHERE     S.ACCOUNT_ID = A.ACCOUNT_ID
                          AND S.STATUS = '1'
                          AND (S.TELEPHONE IS NOT NULL OR S.FAX IS NOT NULL))
复制
SELECT *
  FROM (SELECT row_.*, ROWNUM rownum_
          FROM (  SELECT T.RESOURCE_ID,
                         T.COM_ID,
                         T.RES_TYPE,
                         T.RES_STATUS,
                         T.RES_TITLE,
                         T.RES_NAME,
                         T.RES_CATEGORY,
                         T.RES_PATTERN,
                         T.RES_VSTATUS,
                         T.RES_VID,
                         T.RES_WIDTH,
                         T.RES_HEIGTH,
                         T.RES_SIZE,
                         T.CHE_NO,
                         T.CHEC_NAME,
                         T.CHE_ADVISE,
                         T.CHECK_TIME,
                         T.ADDER_NO,
                         T.ADDER_NAME,
                         T.ADDER_TIME,
                         T.UPDATER_NO,
                         T.UPDATER_NAME,
                         T.UPDATER_TIME,
                         T.RES_COVER_URL,
                         (SELECT NVL (
                                    TO_CHAR (WMSYS.WM_CONCAT (A.RELATION_ID)),
                                    '')
                            FROM XXX.CORE_RES_MAP A
                           WHERE     A.RESOURCE_ID = T.RESOURCE_ID
                                 AND A.DELETE_STATUS = '0'
                                 AND A.RELATION_TYPE = '0')
                            AS PRODUCT_IDS
                    FROM XXX.CORE_PRO_CN_RES T
                   WHERE     T.COM_ID = :1
                         AND T.RESOURCE_TYPE = :2
                         AND T.RESOURCE_VSTATUS = '2'
                         AND T.RESOURCE_STATUS IN (:3)
                ORDER BY T.ADDER_TIME DESC) row_) w
复制

查看SQL查询所使用的表,并无LOB类型字段,可为什么临时表表段类型会是LOB_DATA和LOB_INDEX呢。

通过资料查询到是因为SQL语句里使用了WMSYS.WM_CONCAT函数。WMSYS.WM_CONCAT是Oracle 10G推出的,用来连接字符串,这套库也是从Oracle 10g升级过来的。

WMSYS.WM_CONCAT在不同的数据库版本里返回类型不同,在11.2,0.4前返回是Varchar类型,而在11.2.0.4上返回LOB类型,这套生产库刚好是11.2.0.4。在11G版本,目前推荐LISTAGG函数。

Oracle在对包含lob字段进行读取、修改或写入时均使用临时表空间TEMPORARY LOB_DATA段以缓存形式来存储这些临时数据。如果是通过过应用程序来访问LOB字段时Oracle并不会显式地去关闭或清理临时LOB,
由于Oracle作为服务端并不知道客户端应用程序什么时候结束对LOB临时段的使用,所以难以对LOB临时段进行释放。

如果是Java程序,可通过java.sql.NClob.free()这个方法来释放lob,但这会牵涉到代码的改造,短期很难见到效果。

三、 解决办法

于是到Oracle 官网上搜寻有无解决办法,根据Oracle MOS ( How to Release the Temp LOB Space and Avoid Hitting ORA-1652 (Doc ID 802897.1))文档资料,建议使用
alter session set events ‘60025 trace name context forever’;
通过设置event 60025来强制会话在COMMIT之后强制释放临时表空间上的LOB。

为了测试event 60025是否会对数据库有影响,我先在即将下线的中文网通点上执行了一段时间,观察数据库无异常。于是在另一个测试点设置系统级 alter system set events ‘60025 trace name context forever’;

目前这套生产库在设置event 60025后已运行了近一周时间,目前观察数据库正常,告警日志未出现临时表空间不足的情况。
image.png
目前观察占用临时表空间的LOB类型都不太大。
另外也跟项目组人员反馈,对相关SQL进行业务改造,建议对WMSYS.WM_CONCAT函数改造,使用LISTAGG函数。

最后修改时间:2022-11-29 09:31:13
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论