1

我有一个过程,其中使用其他表列上的 sum 和 nvl 函数填充表的列。这些更新查询很慢,这使得整个 Proc 变慢。这样的更新查询之一如下:

 UPDATE t_final wp
    SET PCT =
        (
        SELECT SUM(NVL(pct,0))
        FROM t_overall
        WHERE rid  = 9
        AND rtype  = 1
        AND sid = 'r12'
        AND pid = 21
        AND mid   = wp.mid
        )
    WHERE rid  = 9 AND rtype  = 1 AND sid = 'r12' AND  pid = 21;

这里 t_overall 和 t_final ,这两个表都没有任何索引,因为它们在整个过程中有多个更新。表 t_final 的记录数约为 8500,表 t_overall 的记录数约为 13000。还有其他方法吗,我可以用更优化的方式编写上述查询吗?

编辑 1:这里 SUM(NVL(pct,0)) 函数首先将表 t_overall 的“pct”列中的 null 替换为 0,然后使用 sum 函数添加所有 pct 值,并根据标准更新表 t_final 的 pct 列。

在下面解释计划回报:

OPERATION                OBJECT_NAME   CARDINALITY  COST
UPDATE STATEMENT                               6     424
 UPDATE                     T_FINAL
   TABLE ACCESS(FULL)       T_FINAL            6     238
   .  Filter Predicates
   .   AND
   .   RTYPE=6
   .   SID='R12'
   .   RID=9    
   .   PID=21
   SORT(AGGREGATE)                             1
    TABLE ACCESS(FULL)      T_OVERALL          1      30
       Filter Predicates
         AND
         MID-:B1
         RTYPE=6
         SID='R12'
         RID=9  
         PID=21

更新的行数约为 2200

编辑 2:我已经使用提示 /*+ collect_plan_statistics */ 运行更新查询,如下所示:

 ALTER session SET statistics_level=ALL;
 UPDATE /*+ gather_plan_statistics */ t_final wp
        SET PCT =
            (
            SELECT SUM(NVL(pct,0))
            FROM t_overall
            WHERE rid  = 9
            AND rtype  = 1
            AND sid = 'r12'
            AND pid = 21
            AND mid   = wp.mid
            )
        WHERE rid  = 9 AND rtype  = 1 AND sid = 'r12' AND  pid = 21;

 select * from
    table (dbms_xplan.display_cursor (format=>'ALLSTATS LAST')); 

结果是:

SQL_ID  gypnfv5nzurb0, child number 1
-------------------------------------
select child_number from v$sql   where sql_id = :1     order by 
child_number

Plan hash value: 4252345203

---------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name                      | Starts | E-Rows | A-Rows |   A-Time   |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |                           |      1 |        |      2 |00:00:00.01 |       |       |          |
|   1 |  SORT ORDER BY           |                           |      1 |      1 |      2 |00:00:00.01 |  2048 |  2048 | 2048  (0)|
|*  2 |   FIXED TABLE FIXED INDEX| X$KGLCURSOR_CHILD (ind:2) |      1 |      1 |      2 |00:00:00.01 |       |       |          |
---------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(("KGLOBT03"=:1 AND "INST_ID"=USERENV('INSTANCE')))

谢谢你。

4

1 回答 1

0

您没有提供足够的信息来进行唯一诊断,所以我只能提示您如何解决您的查询。

这是我的设置模拟您的数据

create table t_final as
select  rownum  mid, 8 + mod(rownum,4) rid,  1 rtype, 'r12' sid, 21 pid, 0 pct from dual
connect by level <= 8800;

drop table T_OVERALL;
create table T_OVERALL as
select  mod(rownum,8800) mid, 8 + mod(rownum,4) rid,  1 rtype, 'r12' sid, 21 pid, rownum pct from dual
connect by level <= 13000;

现在我运行查询来激活统计信息收集以查看查询在做什么:

SQL> UPDATE /*+ gather_plan_statistics */ t_final wp
  2      SET PCT =
  3          (
  4          SELECT SUM(NVL(pct,0))
  5          FROM t_overall
  6          WHERE rid  = 9
  7          AND rtype  = 1
  8          AND sid = 'r12'
  9          AND pid = 21
 10          AND mid   = wp.mid
 11          )
 12      WHERE rid  = 9 AND rtype  = 1 AND sid = 'r12' AND  pid = 21;

2200 rows updated.

Elapsed: 00:00:00.97

所以将近一秒钟的时间过去了,如果你有很多这样的更新,这会很慢。要查看原因,我们显示光标和统计信息(可以使用提示进行历史记录/*+ gather_plan_statistics */

SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------

SQL_ID  3ctaz5gvksb54, child number 0
-------------------------------------
UPDATE /*+ gather_plan_statistics */ t_final wp     SET PCT =         (
        SELECT SUM(NVL(pct,0))         FROM t_overall         WHERE rid
 = 9         AND rtype  = 1         AND sid = 'r12'         AND pid =
21         AND mid   = wp.mid         )     WHERE rid  = 9 AND rtype  =
1 AND sid = 'r12' AND  pid = 21

Plan hash value: 1255260726

-------------------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------

| Id  | Operation           | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT    |           |      1 |        |      0 |00:00:00.96 |     116K|
|   1 |  UPDATE             | T_FINAL   |      1 |        |      0 |00:00:00.96 |     116K|
|*  2 |   TABLE ACCESS FULL | T_FINAL   |      1 |   2200 |   2200 |00:00:00.01 |      33 |
|   3 |   SORT AGGREGATE    |           |   2200 |      1 |   2200 |00:00:00.92 |     112K|
|*  4 |    TABLE ACCESS FULL| T_OVERALL |   2200 |     33 |   3250 |00:00:00.85 |     112K|
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------


   2 - filter(("RID"=9 AND "RTYPE"=1 AND "PID"=21 AND "SID"='r12'))
   4 - filter(("RID"=9 AND "RTYPE"=1 AND "PID"=21 AND "MID"=:B1 AND "SID"='r12'))

因此,您会看到主要问题在于被调用了 2200 次的FULL TABLE SCANon T_OVERALL(列 Starts,第 4 行)。

补救措施可以根据第 4 行的过滤谓词提供一个索引:

create index T_OVERALL_IDX on T_OVERALL(mid, rid, rtype, sid, pid);

现在我得到了相同的数据:

Elapsed: 00:00:00.05

使用现在 2200 INDEX RANGE SCANs的更改计划

--------------------------------------------------------------------------------------------------------- 
| Id  | Operation                     | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT              |               |      1 |        |      0 |00:00:00.05 |   10272 |
|   1 |  UPDATE                       | T_FINAL       |      1 |        |      0 |00:00:00.05 |   10272 |
|*  2 |   TABLE ACCESS FULL           | T_FINAL       |      1 |   2200 |   2200 |00:00:00.01 |      33 |
|   3 |   SORT AGGREGATE              |               |   2200 |      1 |   2200 |00:00:00.01 |    5755 |
|   4 |    TABLE ACCESS BY INDEX ROWID| T_OVERALL     |   2200 |     33 |   3250 |00:00:00.01 |    5755 |
|*  5 |     INDEX RANGE SCAN          | T_OVERALL_IDX |   2200 |      1 |   3250 |00:00:00.01 |    2505 |
--------------------------------------------------------------------------------------------------------- 

使用您的数据简单地重新检查相同的方法,如果您观察到不同的行为,请随时发布它

于 2018-07-03T17:39:57.417 回答