【问题标题】:ORACLE/SQL - Need help optimizing 'merge' style scriptORACLE/SQL - 需要帮助优化“合并”样式脚本
【发布时间】:2012-01-06 23:16:36
【问题描述】:

我们有一个“合并”脚本,用于将代码分配给客户。目前,它通过在临时表中查看客户并为其分配未使用的代码来工作。这些代码被标记为已使用,并且带有代码的分段记录加载到生产表中。暂存台被清理干净,生活变得美好。

不幸的是,我们现在正在处理更大的数据集(包括客户和代码),并且该过程需要很长时间才能运行。我希望这里的优秀社区可以查看这里的代码并提供改进或解决问题的另一种方式。

提前致谢!

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

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

【问题讨论】:

  • 在原帖中添加了一些额外的细节

标签: sql oracle merge


【解决方案1】:
  • 尽可能多地组合语句。例如,通过简单地将“or cust_id is 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。它会更难学习,人们不太可能改变它,因为它看起来很复杂,人们也不太可能看到错误,因为目的不明确。

【讨论】:

  • 非常感谢您的提示 - 现在尝试实施它们!我的 Oracle/SQL 技能没有达到应有的水平 LOL
【解决方案2】:
  • 不要在每个语句之后提交。相反,您应该在脚本末尾发出一个COMMIT。这不是为了提高性能,而是因为直到脚本结束数据才处于一致状态。

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

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

【讨论】:

    猜你喜欢
    • 2013-09-16
    • 2023-01-27
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 1970-01-01
    相关资源
    最近更新 更多