过账:单一分类账运行时间过长

  • Post author:
  • Post category:其他


过账:单一分类账运行时间过长

近期业务反馈”增加/删除汇总账户”程序运行时间长达十几个小时,”过账:单一分类账”时间有时候运行时间长达半个小时。主要的原因是近期新增了很多账套和汇总模板,系统会重新收集各个账套汇总模板和明细账户之间的关系。

通过PLSQL的session查看,程序主要卡在一下两个SQL;

第一个耗费时间的SQL
SELECT 2021, 8,
       sc.code_combination_id,
       dc.code_combination_id,
       dc.SEGMENT4,
       0, sysdate
FROM
 gl_summary_interim_0 si0,
 gl_code_combinations sc,
 gl_code_combinations dc
WHERE  dc.chart_of_accounts_id = 50388
AND  dc.template_id IS NULL
AND  dc.account_type in ('A','L','O','R','E')
AND (dc.code_combination_id BETWEEN 1504966 AND 1515448)
AND  si0.source_flex_value = dc.SEGMENT1
AND  sc.chart_of_accounts_id = 50388
AND  sc.template_id = 8
AND  sc.SEGMENT1 = si0.target_flex_value
AND  sc.SEGMENT2 = dc.SEGMENT2
AND  sc.SEGMENT3 = 'T'
AND  sc.SEGMENT4 = dc.SEGMENT4
AND  sc.SEGMENT5 = 'T'
AND  sc.SEGMENT6 = dc.SEGMENT6
AND  sc.SEGMENT7 = 'T'
AND  sc.SEGMENT8 = 'T'
AND  sc.SEGMENT9 = 'T'
AND NOT EXISTS
      (SELECT 1
       FROM   gl_account_hierarchies ah2
       WHERE  ah2.summary_code_combination_id = sc.code_combination_id
       AND    ah2.detail_code_combination_id = dc.code_combination_id)```

在这里插入图片描述

其实EBS系统GL_CODE_COMBINATIONS的索引是比较奇怪了,仅有GL_CODE_COMBINATIONS_U1唯一性索引和GL_CODE_COMBINATIONS_N31关于模板ID的索引。

这里针对上面SQL出现的两个数字1504966、1515448做一下解释,无论是逐级增删模板还是凭证过账,都会对各个汇总模板的账户关系(汇总账户和明细账户)进行归集,1504966是GL_SUMMARY_TEMPLATES表MAX_CODE_COMBINATION_ID的值,它表示已经归集账户的最大值,1515448表示当前GL_CODE_COMBINATIONS最大的CODE_COMBINATION_ID,系统需要归集这个范围之内的账户。注意明细账户是不区分账套的,汇总账户区分账套的。如果系统新增很多维度比较细的汇总账户,很容易在GL_CODE_COMBINATIONS增加大量账户。上面两个数字差会变大,这是影响上面SQL执行一个因素。

当然最主要的因素还是第六步走GL_CODE_COMBINATIONS_N31,这个索引抓去了7W多条数据,系统又花费了大量时间对这7W条数据其他条件过滤。

结论有两点:

汇总模板的增加会大量增加GL_CODE_COMBINATIONS数据条数,汇总维度越细加的越多。

现有的GL_CODE_COMBINATIONS仅有两个索引,不合理,需要增加合适的索引。

第二个会耗费时间的SQL:
UPDATE gl_temporary_combinations tc1 
SET tc1.code_combination_id = 
(select nvl(cc.code_combination_id, -1) 
from gl_code_combinations cc, gl_temporary_combinations tc2 
where (cc.template_id(+) + 0) = :out_template_id 
  and tc2.chart_of_accounts_id = cc.chart_of_accounts_id(+) 
  and tc2.SEGMENT1 = cc.SEGMENT1(+) 
  and tc2.SEGMENT2 = cc.SEGMENT2(+) 
  and tc2.SEGMENT3 = cc.SEGMENT3(+) 
  and tc2.SEGMENT4 = cc.SEGMENT4(+) 
  and tc2.SEGMENT5 = cc.SEGMENT5(+) 
  and tc2.SEGMENT6 = cc.SEGMENT6(+) 
  and tc2.SEGMENT7 = cc.SEGMENT7(+) 
  and tc2.SEGMENT8 = cc.SEGMENT8(+) 
  and tc2.SEGMENT9 = cc.SEGMENT9(+) 
  and tc2.rowid = tc1.rowid) 
where request_id = :req_id

SQL执行计划

这个SQL执行路径就有点过分了,对GL_CODE_COMBINATIONS全表扫描,然后在按字段过滤。耗费了大量的时间。

在metlink上参考Doc 858725.1,对GL_CODE_COMBINATIONS增加合适的索引,过程如下:

DECLARE
   v_SegNum VARCHAR2(9);
   v_FreqCount NUMBER;
BEGIN
   FOR i IN 1..30
   LOOP
      EXECUTE IMMEDIATE
         'SELECT COUNT(DISTINCT SEGMENT'||TO_CHAR(i)||')
         FROM gl_code_combinations'
      INTO v_FreqCount ;
      IF v_freqCount <> 0 THEN
          DBMS_OUTPUT.PUT_LINE(
             'SEGMENT'||TO_CHAR(i)||' Frequency = '||TO_CHAR(v_FreqCount));
      END IF;
   END LOOP;
END;

查询结果假如如下:

SEGMENT1 Frequency = 4

SEGMENT2 Frequency = 37

SEGMENT3 Frequency = 76

SEGMENT4 Frequency = 3221

SEGMENT5 Frequency = 21

SEGMENT6 Frequency = 22

从细到粗建组合索引:

CREATE INDEX GL_CODE_COMBINATIONS_CAT ON gl_code_combinations
   (segment4,
    segment3,
    segment2,
    segment6,
    segment5,
    segment1)
PCTFREE 0
INITRANS 2
MAXTRANS 255
TABLESPACE user_index
STORAGE (INITIAL 1048576
    NEXT 16384
    PCTINCREASE 0
    MINEXTENTS 1
    MAXEXTENTS 20);

按照上诉步骤执行后,执行统计数据收集表请求或执行以下SQL收集表:

BEGIN
  fnd_stats.gather_table_stats('GL'
                              ,'GL_CODE_COMBINATIONS'
                              ,dbms_stats.auto_sample_size);
END;

增加/删除汇总账户原本运行时间十几个小时,限制只需要运行40s;查看第二个SQL执行计划如下图,发现耗费时间巨大缩短:

在这里插入图片描述

其实最后发现解决问题的办法很简单,只是增加了一个索引哈。但个人觉得处理问题的思路还是可以借鉴一下。



版权声明:本文为longtimetoc原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。