Oracle SQL - 非常昂贵的更新声明?

时间:2013-01-29 00:07:18

标签: sql oracle sql-update

我有这样的声明:

update new_table t2
set t2.creation_date_utc =
(select creation_date from old_table t1 where t2.id = t1.id)
where exists
(select 1 from old_table t1 where t2.id = t1.id);

根据解释计划的成本是150959919.解释计划显示了一些完整的表访问,总成本类似于3000,然后更新具有基本上无限的成本。如果跑步,它确实似乎永远存在。

仅供参考,这些表每行不超过300k行。

另外,这个查询。

select 
(select creation_date from old_table t1 where t2.id = t1.id)
from new_table t2;

基本上立即完成。

这可能是什么原因?

4 个答案:

答案 0 :(得分:3)

如果你有一个你提到的格式的更新语句,那么它意味着id字段在old_table中是唯一的(否则第一个内部查询会引发错误,返回多个值以进行更新,实际上只有一个值可以处理)。因此,您可以修改您的第一个查询(删除where子句,因为它是多余的): -

update new_table t2
set t2.creation_date_utc =
(select creation_date from old_table t1 where t2.id = t1.id);

由于全表扫描,上述查询可能仍需要很长时间。所以,你有两个选择: -

  1. 使用以下命令将索引应用于id字段上的old_table表。

    Create index index_name on old_table(id);
    
  2. 将您的更新查询修改为以下(未经测试): -

    update new_table t2
    set t2.creation_date_utc=
    (select creation_date from old_table t1 where t2.id=t1.id and rownum=1);
    
  3. rownum = 1应该指示oracle在old_table中找到第一个匹配项后不再进行搜索。

    我会推荐第一种方法。

答案 1 :(得分:2)

你没有old_table.id上的索引,嵌套循环连接非常昂贵。 old_table(id,creation_date)的索引最好。

答案 2 :(得分:1)

为什么不使用merge语句?我发现它在类似情况下更有效率。

merge into new_table t2
using old_table t1 
on (t2.id = t1.id)
when matched then
    update set t2.creation_date_utc = t1.creation_date;

答案 3 :(得分:0)

这可能更快,更等效:

update new_table t2
set t2.creation_date_utc =
(select creation_date from old_table t1 where t2.id = t1.id)
where t2.id in
(select id from old_table t1);