Oracle简单更新语句,POOR性能

时间:2011-12-21 08:16:16

标签: sql database oracle oracle11g

我有一个包含大数据(大约1000万条记录)的表格,因此最简单的更新语句永远都可以使用。

例如:

update mesg 
set archived = 1
    , last_update = SYSDATE 
where id = 0 
and crea_date_time < '07/27/2011 13:53:36'  
and archived = 0;

此声明大约需要3个小时。虽然我们在id上有索引,在crea_date_time上有复合索引,但没有触发器。

我是否可以采取任何改进措施来提高效果。

我尝试在存档上添加索引但没有效果。


这里有一些额外的信息。

CREATE TABLE "MESG"
  (
    "ID"                        NUMBER(3,0) NOT NULL ENABLE,
    "UMIDL"                     NUMBER(10,0) NOT NULL ENABLE,
    "UMIDH"                     NUMBER(10,0) NOT NULL ENABLE,
    .
    .
    .
    "ARCHIVED"          NUMBER(1,0) NOT NULL ENABLE,
    "LAST_UPDATE" DATE,
    "CREA_DATE_TIME" DATE NOT NULL ENABLE,
    .
    .
    .
    CONSTRAINT "PK_RMESG" PRIMARY KEY ("AID", "UMIDH", "UMIDL") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "XXXX_IDX" ENABLE
  )

  SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE
  (
    INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )
  TABLESPACE "XXXX_MESG" ;

索引:

CREATE INDEX "E_RCREATIONDATE" ON "RMESG"
  (
    "CREA_DATE_TIME"
  )
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE
  (
    INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )

  TABLESPACE "XXXX_IDX" ;
CREATE UNIQUE INDEX "PK_RMESG" ON "RMESG"
  (
    "ID", "UMIDH", "UMIDL"
  )
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE
  (
    INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )
  TABLESPACE "XXXX_IDX" ;

并且查询计划适用于具有180K记录的本地计算机

ID   PID   Operation   Name   Rows   Bytes   Cost   CPU Cost   IO Cost   Temp space   IN-OUT   PQ Dist   PStart   PStop
0      UPDATE STATEMENT      1    44    877    6245703    877                       
1   0     UPDATE   MESG                                           
2   1       TABLE ACCESS BY INDEX ROWID   MESG   1    44    877    6245703    877                       
3   2         INDEX RANGE SCAN   IX_MESG_CREATIONDATE   158K       877    6245703    877                       

6 个答案:

答案 0 :(得分:2)

我假设存档是 - boolean,可以是0或1.在这种情况下,优化器可能会选择忽略索引。

为了验证是否使用了索引,您可以尝试

explain plan for
   update mesg set archived = :a, 
                   last_update = :b 
     where id = :c and 
            crea_date_time < :d and 
            archived = :e;  

然后

select * from table(dbms_xplan.display);

答案 1 :(得分:1)

如果您更新了很多行,索引将无法帮助您。它们只会改善对数据的访问。

对你而言,最重要的是UPDATE本身。

一个。用户是否读取/更新了此表?

如果没有,您可以尝试使用新数据重新创建表。

create table copy_table as
select case 
       when s.archived = 0 and s.crea_date_time < '07/27/2011 13:53:36' and s.id = 0
       then 1 else s.archived as archived,
       when s.archived = 0 and s.crea_date_time < '07/27/2011 13:53:36' and s.id = 0
       then sysdate else s.last_update_date as last_update_date,
       id,
       other_columns
from mesg;

rename mesg to mesg_old;
rename copy_table to mesg;

B中。另一个想法/帮助是,如果你有许可证,可以在crea_date_time上对你的mesg表进行分区(我假设它是date类型)。 在这种情况下,您的更新不会扫描整个表,但更重要的是,您可能永远不需要将其标记为存档内容。旧分区 - 旧数据。

℃。 CREA_DATE_TIME上的索引正在减慢您的更新。如果不是绝对必要,请放弃它。

答案 2 :(得分:1)

首先你真的想要跑:

update mesg  
set archived = 1     
, last_update = SYSDATE  
where id = 0  and crea_date_time < '07/27/2011 13:53:36'  
and archived <>1

(对于ORacle来说是正确的代码吗?或者确实是使用!=?或者可能存档的位置为null或者存档= 0,以及如何存储数据)

现在,您正在更改已归档的所有记录的last_update日期和已归档字段。因此,您可以更新已存档的数百万条记录。因此,不是更新自上次执行以来需要存档的120,000条记录,而是更新35,000,000条记录,其中大多数已经存档。可以在性能方面做出很大改变,只更新需要更新的记录。

接下来我不了解Oracle,但有时在SQl Server中批量运行大型更新/插入/删除会更快。那你有没有试过循环1000(或50000你可能需要测试,看看什么有效)?这可以减少桌面上的大量争用并使事情更快地运行。

答案 3 :(得分:1)

索引不是问题。这是更新。

我认为你必须深入等待分析,字典表v $ session_waits。如果您具有企业管理器数据库控制,则可以使用性能工具查看导致延迟的原因。我的猜测是,它与重做日志的IO性能有关,或者其他人提到锁定问题。

首先:

select
 seq#, event, p1, p2, p3
from
 v$session_wait_history
where
sid = <yoursid>
order by seq#
;   

谷歌在oracle等待分析中,你会发现很多材料。

答案 4 :(得分:0)

即使是数据量,三个小时太长了。

您可以尝试修改查询以避免类型转换,将to_data函数应用于您的日期字符串(将此'07 / 27/2011 13:53:36'转换为日期)

问题应该是锁,您可以使用Killing an oracle session to remove a lock脚本检查锁定。

此外,您可以在小更新中拆分大查询,有些人认为:

for each year:
   begin transaction
   update statement where year(date) = @year and other conditions
   end transaction

答案 5 :(得分:0)

您应该进行表分区和索引分区。 性能会提高