【问题标题】:Optimizing sql update syntax rather than the Server优化 sql 更新语法而不是服务器
【发布时间】:2013-11-24 03:47:33
【问题描述】:

有两张表,一张正在根据第二张表进行更新。 SQL 正在工作,但我认为,由于记录数量的原因,它花费了太多时间。见this小提琴。实际主表包含 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 的解决方案将不起作用

【问题讨论】:

    标签: sql oracle optimization oracle11g query-optimization


    【解决方案1】:

    看看这个:

    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。

    【讨论】:

    • 嗯,基本区别在于,在我的情况下,seqnnot nullunique index,但不是 primary key。因此,它表明Primary KeyUnique Index + Not Null 是不同的!!!
    • 确实很有趣。至少对于这种操作!
    • 即使在将seqn 修改为Primary Key 之后仍然会出现同样的错误,可能是因为我的版本是11.1 而sqlfiddle 使用的是11.2。
    • 这么有趣,你能调查一下吗?
    • 有趣!如果childseqnUniquePrimary Key,则查询将起作用。 master 什么都不需要
    猜你喜欢
    • 2016-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 2016-01-24
    • 1970-01-01
    相关资源
    最近更新 更多