ORACLE / SQL - 需要帮助优化'merge'样式脚本

时间:2011-11-26 16:35:46

标签: sql oracle merge

我们有一个'merge'脚本,用于为客户分配代码。目前,它的工作原理是在临时表中查看客户并为其分配未使用的代码。这些代码被标记为已使用,并且带有代码的分阶段记录被加载到生产表中。临时表被清除,生命很好。

不幸的是,我们现在正在使用更大的数据集(包括客户和代码),并且该流程需要花费很长时间才能运行。我希望这里的精彩社区可以在这里查看代码,并提供改进或其他方式来解决问题。

提前致谢!

编辑 - 忘记提及部分检查的部分原因是临时表是“活的”并且可以在脚本运行期间输入记录。

whenever sqlerror exit 1

-- stagingTable: TAB_000000003134
-- codeTable: TAB_000000003135
-- masterTable: TAB_000000003133

-- dedupe staging table
delete from TAB_000000003134 a
where ROWID > (
  select min(rowid)
  from TAB_000000003134 b
  where a.cust_id = b.cust_id
  );
commit;

delete from TAB_000000003134
where cust_id is null;
commit;


-- set row num on staging table
update TAB_000000003134
set row_num = rownum;
commit;

-- reset row nums on code table
update TAB_000000003135
set row_num = NULL;
commit;

-- assign row nums to codes
update TAB_000000003135
set row_num = rownum
where dateassigned is null
and active = 1;
commit;

-- attach codes to staging table
update TAB_000000003134 d
set (CODE1, CODE2) =
(
  select CODE1, CODE2
  from TAB_000000003135 c
  where d.row_num = c.row_num
);
commit;

-- mark used codes compared to template
update TAB_000000003135 c
set dateassigned = sysdate, assignedto = (select cust_id from TAB_000000003134 d where c.CODE1 = d.CODE1)
where exists (select 'x' from TAB_000000003134 d where c.CODE1 = d.CODE1);
commit;

-- clear and copy data to master
truncate table TAB_000000003133;
insert into TAB_000000003133 (
        <custmomer fields>, code1, code2, TIMESTAMP_
        )
select <custmomer fields>, CODE1, CODE2,SYSDATE
from TAB_000000003134;
commit;

-- remove any staging records with code numbers
delete from TAB_000000003134
where CODE1 is not NULL;
commit;

quit

2 个答案:

答案 0 :(得分:1)

  • 尽可能地合并陈述。例如,通过简单地将“或cust_id为null”添加到第一个删除来组合前两个删除。这肯定会减少读取次数,也可能会显着减少写入的数据量。 (Oracle写入块而不是行,所以即使这两个语句使用不同的行,它们也可能会重写相同的块。)
  • 将整个表插入另一个表可能比更新每一行更快。 Oracle为更新和删除做了很多额外的工作,以保持并发性和一致性。将值更新为NULL可能会特别昂贵,有关详细信息,请参阅update x set y = null takes a long time。您可以使用直接路径插入来避免(几乎所有)UNDO和REDO:确保表处于NOLOGGING模式(或数据库处于NOARCHIVELOG模式),并使用APPEND提示进行插入。
  • 用MERGE替换UPDATE。 UPDATE只能使用嵌套循环,MERGE也可以使用散列连接。如果您要更新大量数据,MERGE可以明显更快。如果它用于SET和EXISTS,则MERGE不必读取表格两次。 (虽然创建新表也可能更快。)
  • 使用/ * + APPEND * /与TAB_000000003133插入。如果您正在截断表,我假设您不需要时间点恢复数据,因此您不妨将其直接插入数据文件并跳过所有开销。
  • 使用并行性(如果您还没有)。调整需要考虑副作用和许多因素,但不要让这些因素沮丧。如果您正在处理大量数据,那么如果您想要充分利用硬件,则迟早需要使用并行性。
  • 使用更好的名字。这个建议更主观,但在我看来,我认为使用好名字是非常重要的。虽然它在某种程度上都是0和1,并且许多程序员认为神秘的代码很酷,但是你希望人们理解和关心你的数据。人们不会像TAB_CUSTOMER_CODES那样关心TAB_000000003135。它会更难学,人们不太可能改变它,因为它看起来很复杂,人们不太可能看到错误,因为目的不明确。

答案 1 :(得分:0)

  • 每次发言后都不要提交。相反,您应该在脚本末尾发出一个COMMIT。这不仅仅是性能,而是因为在脚本结束之前数据不是一致的状态。

(事实证明,在Oracle中提交频率可能较低performance benefits,但您主要关心的是保持一致性)

  • 您可以考虑使用global temporary tables。全局临时表中的数据仅对当前会话可见,因此您可以跳过脚本中的一些重置步骤。