【问题标题】:Oracle UPDATE performance issue and optimizationOracle UPDATE 性能问题和优化
【发布时间】:2011-10-21 09:54:56
【问题描述】:

让我们来做一个我遇到很多问题的查询。

表 *CONF_ELEMENTI_FATTURABILI* 大小为 160 Gb,并在 edw_partition 字段中分区为 2587 个分区(但并行性在第二个查询中不起作用)。 *BCK_MEM_ANIMALI_F_ROPT_ELF* 和 *INT_TEMP51* 非常相似。它们有索引并包含 90k 记录(第二个是第一个的 GROUP BY)。 更新基于PK。所以正好有 90k 条记录被更新了。

在 30' 后,以下更新查询不会结束。我怎么知道它是否有效。 并行执行不起作用(除一个之外的所有线程都处于空闲状态)。为什么?我应该强制执行一些 FULL 表/索引扫描吗?

CONF_ELEMENTI_FATTURABILI 的其他详细信息:
大小:161419,19 MB
号码范围:140964
NUM_ROWS:262000000(2.6 亿)
积木:10241238
分区:是 - 2587 个分区

第一个配方

alter session enable parallel dml;

UPDATE  
    CONF_ELEMENTI_FATTURABILI elf
   SET   ELF_ELEMENTO_CHIUSO = 'C',
         ELF_DATA_VER_FIN =
            (  SELECT   TELE_DATA_LETTURA
                 FROM   NETATEMP.int_temp51 t
                WHERE   t.ELF_STORICO_ID = elf.ELF_STORICO_ID
                AND t.edw_partition = elf.edw_partition)
WHERE   exists (SELECT  1 FROM netatemp.bck_mem_animali_f_ropt_elf kk WHERE   kk.ELF_STORICO_ID = elf.ELF_STORICO_ID
                AND kk.edw_partition = elf.edw_partition);

解释计划:

Plan
UPDATE STATEMENT  ALL_ROWSCost: 87,99  Bytes: 6.269.021  Cardinality: 85,877                
    8 UPDATE SIUCONTRATTI.CONF_ELEMENTI_FATTURABILI             
        5 NESTED LOOPS  Cost: 87,99  Bytes: 6.269.021  Cardinality: 85,877          
            2 SORT UNIQUE  Cost: 67  Bytes: 1.975.171  Cardinality: 85,877      
                1 INDEX FAST FULL SCAN INDEX SIUINTEGRA.MEMBR_4 Cost: 67  Bytes: 1.975.171  Cardinality: 85,877  
            4 PARTITION LIST ITERATOR  Cost: 2  Bytes: 50  Cardinality: 1  Partition #: 5   
                3 INDEX RANGE SCAN INDEX (UNIQUE) SIUCONTRATTI.CONF_ELF_UK_IDX1 Access Predicates: "KK"."ELF_STORICO_ID"="ELF"."ELF_STORICO_ID" AND "KK"."EDW_PARTITION"="ELF"."EDW_PARTITION"  Cost: 2  Bytes: 50  Cardinality: 1  Partition #: 5  
        7 TABLE ACCESS BY INDEX ROWID TABLE SIUINTEGRA.INT_TEMP51 Cost: 69  Bytes: 256  Cardinality: 8          
            6 INDEX RANGE SCAN INDEX SIUINTEGRA.MEMBR_6 Access Predicates: "T"."ELF_STORICO_ID"=:B1  Cost: 2  Cardinality: 333      

第二个公式

UPDATE  
    CONF_ELEMENTI_FATTURABILI elf
   SET   ELF_ELEMENTO_CHIUSO = 'C',
         ELF_DATA_VER_FIN =
            (  SELECT   TELE_DATA_LETTURA
                 FROM   int_temp51 t
                WHERE   t.ELF_STORICO_ID = elf.ELF_STORICO_ID
                AND t.edw_partition = elf.edw_partition)
 WHERE   (ELF_STORICO_ID, edw_partition) IN (SELECT /*+ full(kk) parallel(kk, 20) */  ELF_STORICO_ID, edw_partition FROM bck_mem_animali_f_ropt_elf kk);

解释计划:

Plan
UPDATE STATEMENT  ALL_ROWSCost: 7,168  Bytes: 6.269.021  Cardinality: 85,877                                    
    13 UPDATE SIUCONTRATTI.CONF_ELEMENTI_FATTURABILI                                
        10 PX COORDINATOR                           
            9 PX SEND QC (RANDOM) SYS.:TQ10001 Cost: 7,168  Bytes: 6.269.021  Cardinality: 85,877                       
                8 NESTED LOOPS  Cost: 7,168  Bytes: 6.269.021  Cardinality: 85,877                      
                    5 SORT UNIQUE  Cost: 7  Bytes: 1.975.171  Cardinality: 85,877               
                        4 PX RECEIVE  Cost: 7  Bytes: 1.975.171  Cardinality: 85,877            
                            3 PX SEND HASH SYS.:TQ10000 Cost: 7  Bytes: 1.975.171  Cardinality: 85,877          
                                2 PX BLOCK ITERATOR  Cost: 7  Bytes: 1.975.171  Cardinality: 85,877     
                                    1 TABLE ACCESS FULL TABLE SIUINTEGRA.BCK_MEM_ANIMALI_F_ROPT_ELF Cost: 7  Bytes: 1.975.171  Cardinality: 85,877  
                    7 PARTITION LIST ITERATOR  Cost: 2  Bytes: 50  Cardinality: 1  Partition #: 10                  
                        6 INDEX RANGE SCAN INDEX (UNIQUE) SIUCONTRATTI.CONF_ELF_UK_IDX1 Access Predicates: "ELF_STORICO_ID"="ELF_STORICO_ID" AND "EDW_PARTITION"="EDW_PARTITION"  Cost: 2  Bytes: 50  Cardinality: 1  Partition #: 10           
        12 TABLE ACCESS BY INDEX ROWID TABLE SIUINTEGRA.INT_TEMP51 Cost: 69  Bytes: 256  Cardinality: 8                             
            11 INDEX RANGE SCAN INDEX SIUINTEGRA.MEMBR_6 Access Predicates: "T"."ELF_STORICO_ID"=:B1  Cost: 2  Cardinality: 333                         

只有一个线程有效!!!

等待:

ROWNUM   SID    EVENT                         TOTAL_WAITS  TOTAL_TIMEOUTS  TIME_WAITED  AVERAGE_WAIT  MAX_WAIT  TIME_WAITED_MICRO                      
1        1012   latch: cache buffers chains             8               0            0          0            0                270    
2        1012   read by other session                 366               0          141          0,38         3            1407428
3        1012   db file sequential read              1287               0          772          0,6          4            7718838
7        1012   events in waitclass Other              40              38         7613        190,33       195           76130586                               
5        1012   PX Deq: Execution Msg                   3               0            8          2,61         4              78312  
6        1012   PX Deq: Table Q Normal                  2               0            1          0,34         1               6763   
4        1012   cursor: pin S wait on X                 1               1            1          0,98         1               9829   
8        1114   latch: cache buffers chains             3               0            0          0            0                 43     
9        1114   read by other session                 381               0          131          0,34         4            1308282
10       1114   db file sequential read              1416               0          841          0,59         4            8410582
11       1114   cursor: pin S wait on X                 1               1            1          0,98         1               9793   
12       1114   PX Deq: Execution Msg                   3               0            8          2,65         4              79609  
13       1114   PX Deq: Table Q Normal                  2               0            1          0,37         1               7441   
14       1114   events in waitclass Other              41              38         7576        184,78       195           75758618                               
15       1154   latch: cache buffers chains             8               0            0          0            0                163    
16       1154   read by other session                 368               0          141          0,38         3            1412020
17       1154   db file sequential read              1819               0         1156          0,64         3           11555685                               
18       1154   cursor: pin S wait on X                 1               1            1          0,98         1               9833   
19       1154   PX Deq: Execution Msg                   3               0            8          2,66         4              79754  
20       1154   PX Deq: Table Q Normal                  2               0            1          0,36         1               7147   
21       1154   events in waitclass Other              38              35         7113        187,19       195           71130875                               
22       1398   latch: cache buffers chains             4               0            0      

IO

SID    BLOCK_GETS  CONSISTENT_GETS  PHYSICAL_READS  BLOCK_CHANGES   CONSISTENT_CHANGES                     
1012            0             9006            1805              0                    0      
1114            0             9999            2393              0                    0      
1154            0            10056            2668              0                    0      
1398            0            10007            1917              0                    0      
1597            0            10058            2046              0                    0      
1649            0            10074            2261              0                    0      
2279        92557         21996787        11908995         170829                  206    
2322            0            10026            1863              0                    0      
2460            0            10082            1927              0                    0      
2479            0             9978            2006              0                    0      
2694            0             9996            2462              0                    0      
2800            0             8641            1767              0                    0      
2829            0            10003            1855              0                    0      
2840            0            10049            2280              0                    0      
2888            0            10038            2574              0                    0      
2998            0             9993            1995              0                    0      
3147            0             8607            1569              0                    0      
3186            0            10021            2478              0                    0      
3219            0            10055            1773              0                    0      
3227            0             9998            2678              0                    0      
3228            0            10003            3083              0                    0  

【问题讨论】:

    标签: sql performance oracle parallel-processing sql-update


    【解决方案1】:

    尽管提供了很多信息,但我不确定这里是否真的有足够有用的信息来帮助回答这个问题,但我会试一试。获取有关表键的一些信息以及您希望在此处更新的行数会很有用。

    如果要更新的表有 262M 行,而包含要更新的数据的表有 90k 记录,那么您可能会尝试根据键更新 90k 到 262M 行之间的任何位置。

    根据我的经验,编写更新有点困难。优化器永远不会按照您想要的方式对待它们。它们对于更新少数行或将列更新为常量值 (SET ELF_ELEMENTO_CHIUSO = 'C') 很有用,但如果您需要在另一个表中查找这些值,它们就不是很好了。 SET 子句中的子查询似乎经常为表中的每一行调用。

    出于这个原因,我通常会尝试编写MERGE 语句或UPDATE 视图。这两种方法都有轻微的缺点,尤其是更新视图,因为需要注意很多限制,这里最重要的一个是它需要是一个保留键的表。此处定义了一个密钥保留表http://download.oracle.com/docs/cd/B19306_01/server.102/b14231/views.htm#sthref3058

    我认为在这种情况下,在创建视图时,您的表 CONF_ELEMENTI_FATTURABILI 应该保留密钥。因此,使用表格更新视图的示例是

    UPDATE (
      select
        elf.ELF_STORICO_ID,
        elf.edw_partition,
        elf.ELF_ELEMENTO_CHIUSO,
        elf.ELF_DATA_VER_FIN,
        t.TELE_DATA_LETTURA
      from 
        CONF_ELEMENTI_FATTURABILI elf
        join NETATEMP.int_temp51 t on (t.ELF_STORICO_ID = elf.ELF_STORICO_ID and
                                       t.edw_partition = elf.edw_partition)
      ) a
    set 
      a.ELF_ELEMENTO_CHIUSO = 'C',
      a.ELF_DATA_VER_FIN = a.TELE_DATA_LETTURA;
    

    由于密钥保存问题,我不能真正保证这会奏效。它可能会,也可能不会。即使是我自己的数据,我也很难计算出来。

    另一个选项是MERGE 语句。这更有可能奏效,因为它不依赖于密钥保存,但我也遇到了奇怪的问题。

    合并的一个例子是:

    MERGE INTO CONF_ELEMENTI_FATTURABILI elf
    USING NETATEMP.int_temp51 t on (t.ELF_STORICO_ID = elf.ELF_STORICO_ID and
                                    t.edw_partition = elf.edw_partition)
    WHEN MATCHED THEN UPDATE SET elf.ELF_ELEMENTO_CHIUSO = 'C',
                                 elf.ELF_DATA_VER_FIN = t.TELE_DATA_LETTURA
    

    正如我在上面所说的,我确信上面显示的任何一个语句都会真正起作用,因为它们都有些繁琐,并且有一些原因导致它们都失败了。希望你能得到一些工作。

    【讨论】:

    • 非常感谢,真的是一个很好的答案! 另一个问题,为什么并行不起作用?
    • 我从来没有在并行方面取得很大成功,但我认为您还需要在UPDATE 语句中添加并行提示。所以你需要UPDATE /*+ parallel(elf) */ CONF_ELEMENTI_FATTURABILI elf...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多