2

有两张表,一张正在根据第二张表进行更新。SQL 正在工作,但我认为,由于记录数量的原因,它花费了太多时间。看到这个小提琴。实际主表包含 1,500,000 条记录,子表包含 700,000 条记录,以下 sql 持续执行 4 小时,因此终止。

UPDATE master m SET m.amnt = (SELECT amnt FROM child c WHERE c.seqn = m.seqn)
WHERE m.seqn IN (SELECT seqn FROM child);

这条sql的执行计划是(红色的一个是master,另一个是child)

在此处输入图像描述

seqn是主键。毫无疑问,这一切都取决于服务器的性能和索引统计。但是,令我困扰的是,索引没有访问主节点,而子节点被读取了两次。sql 可能已优化,但 oracle 决定采用这种方式,但是我尝试将 sql 优化为

UPDATE (
SELECT m.seqn m_seqn,c.seqn c_seqn, c.amnt c_amnt, m.amnt m_amnt
FROM master m INNER JOIN child c ON m.seqn = c.seqn) 
SET m_amnt = c_amnt

这导致了以下错误

ORA-01779: cannot modify a column which maps to a non key-preserved 
table : UPDATE ( SELECT m.seqn m_seqn,c.seqn c_seqn, c.amnt c_amnt, m.amnt m_amnt 
FROM master m INNER JOIN child c ON m.seqn = c.seqn) SET m_amnt = c_amnt

除了更新统计信息和调整服务器之外,我还有什么方法可以优化 SQL 吗?

编辑如果要加入的列不是 PK,@Sebas 的解决方案将不起作用

4

1 回答 1

2

看看这个:

UPDATE  
(
    SELECT m.amnt AS tochange, c.amnt AS newvalue 
    FROM child c 
        JOIN master m ON c.seqn = m.seqn
) t
SET t.tochange = t.newvalue;

SELECT * FROM master;

小提琴:http ://www.sqlfiddle.com/#!4/c6b73/2

你只是错过了小提琴中的PK。

于 2013-11-12T05:43:39.667 回答