Oracle多表关联更新

更新原则:
1)更新的时候一定要加where条件,否则必然引起该字段的所有记录更新
2)跨表更新时,set和where时,尽量减少扫描次数,从而提高优化

一.最简单的形式-单表更新

--确认业务逻辑,筛选条件都在一个表内,进行单表更新
UPDATE CUSTOMERS SET CITY_NAME = '北京' WHERE CUSTOMER_ID < 1000;

二.两表(多表)关联update – set为简单的数据(直接是值),且仅在where字句中的连接

--这次提取的数据都是VIP,且包括新增的,所以顺便更新客户类别
UPDATE CUSTOMERS A -- 使用别名
   SET CUSTOMER_TYPE = '01' --01 为vip,00为普通
 WHERE EXISTS (SELECT 1 FROM TMP_CUST_CITY B WHERE B.CUSTOMER_ID = A.CUSTOMER_ID);

三.两表(多表)关联update – 被修改值由另一个表运算而来

UPDATE CUSTOMERS A -- 使用别名
   SET CITY_NAME =
        (SELECT B.CITY_NAME FROM TMP_CUST_CITY B WHERE B.CUSTOMER_ID = A.CUSTOMER_ID)
 WHERE EXISTS (SELECT 1 FROM TMP_CUST_CITY B WHERE B.CUSTOMER_ID = A.CUSTOMER_ID);

优化:单个字段的优化,简化为扫描一遍

UPDATE CUSTOMERS A -- 使用别名
   SET CITY_NAME = NVL((SELECT B.CITY_NAME
                          FROM TMP_CUST_CITY B
                         WHERE B.CUSTOMER_ID = A.CUSTOMER_ID),
                        A.CITY_NAME);

update 超过2个值(字段)

UPDATE CUSTOMERS A -- 使用别名
   SET (CITY_NAME, CUSTOMER_TYPE) =
        (SELECT B.CITY_NAME, B.CUSTOMER_TYPE
           FROM TMP_CUST_CITY B
          WHERE B.CUSTOMER_ID = A.CUSTOMER_ID)
 WHERE EXISTS (SELECT 1 FROM TMP_CUST_CITY B WHERE B.CUSTOMER_ID = A.CUSTOMER_ID);
 --缺陷:就是对表B进行两遍扫描

四.内联视图更新 与 merge更新

UPDATE (SELECT T1.FMONEY FMONEY1, T2.FMONEY FMONEY2 FROM T1, T2 WHERE T1.FNAME = T2.FNAME) T
   SET FMONEY1 = FMONEY2;
MERGE INTO T1
USING (SELECT T2.FNAME, T2.FMONEY FROM T2) T
ON (T.FNAME = T1.FNAME)
WHEN MATCHED THEN
    UPDATE SET T1.FMONEY = T.FMONEY;

五.特殊情况的优化:

因为B表的纪录只有A表的20-30%的纪录数,且 A表使用INDEX的情况 使用cursor也许会比关联update带来更好的性能:

DECLARE
    SET SERVEROUTPUT ON DECLARE CURSOR CITY_CUR IS
        SELECT CUSTOMER_ID, CITY_NAME FROM TMP_CUST_CITY ORDER BY CUSTOMER_ID;
BEGIN
    FOR MY_CUR IN CITY_CUR LOOP
        UPDATE CUSTOMERS
           SET CITY_NAME = MY_CUR.CITY_NAME
         WHERE CUSTOMER_ID = MY_CUR.CUSTOMER_ID;
        /** 此处也可以单条/分批次提交,避免锁表情况 **/
    -- if mod(city_cur%rowcount,10000)=0 then
    -- dbms_output.put_line('----');
    -- commit;
    -- end if;
    END LOOP;
END;

六.关联update的一个特例以及性能再探讨

在oracle的update语句语法中,除了可以update表之外,也可以是视图,所以有以下1个特例:

UPDATE (SELECT A.CITY_NAME, B.CITY_NAME AS NEW_NAME
           FROM CUSTOMERS A, TMP_CUST_CITY B
          WHERE B.CUSTOMER_ID = A.CUSTOMER_ID)
   SET CITY_NAME = NEW_NAME;

这样能避免对B表或其索引的2次扫描,但前提是 A(customer_id) b(customer_id)必需是unique index或primary key

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐