1. 程式人生 > 資料庫 >Oracle使用遊標進行分批次更新資料的6種方式及速度比對

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

1.情景展示

  一共有22w條資料,需要將A表的主鍵更新至B表的指定欄位,如何快速完成更新?

2.解決方案

  宣告:

  解決方案不只一種,該文章只介紹快速遊標法及程式碼實現;

  兩張表的ID和ID_CARD欄位都建立了索引。

  方式一:使用隱式遊標(更新一次提交1次)

--快速遊標法
BEGIN
FOR TEMP_CURSOR IN (SELECT T2.ID,T2.ID_CARD
FROM VIRTUAL_CARD10 T1,PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區資料'
AND T2.REMARK = '**市****區資料') LOOP
/* LOOP迴圈的是TEMP_CURSOR(逐條讀取TEMP_CURSOR) */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = TEMP_CURSOR.ID
WHERE ID_CARD = TEMP_CURSOR.ID_CARD;
COMMIT; --提交
END LOOP;
END;

  執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  方式二:使用隱式遊標(更新1000次提交1次)(推薦使用)

/* 使用隱式遊標進行分批次更新 */
DECLARE
 V_COUNT NUMBER(10);
BEGIN
 /* 隱式遊標 */
 FOR TEMP_CURSOR IN (SELECT T2.ID,T2.ID_CARD
            FROM VIRTUAL_CARD10 T1,PRIMARY_INDEX10 T2
            WHERE T1.ID_CARD = T2.ID_CARD
             AND T1.REMARK = '**市****區資料'
             AND T2.REMARK = '**市****區資料') LOOP
  /* 業務邏輯 */
  UPDATE VIRTUAL_CARD10
    SET INDEX_ID = TEMP_CURSOR.ID
   WHERE ID_CARD = TEMP_CURSOR.ID_CARD;
  /* 更新一次,+1 */
  V_COUNT := V_COUNT + 1;
  /* 1000條提交1次 */
  IF V_COUNT >= 1000 THEN
   COMMIT; --提交
   V_COUNT := 0; --重置
  END IF;
 END LOOP;
 COMMIT; -- 提交所有資料,把這個去掉,可以檢視是否是自己想要的效果,再決定是否提交
END;

  執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  方式三:顯式遊標+分批次更新(1000條1提交)

/* 使用遊標進行分批次更新 */
DECLARE
V_COUNT NUMBER(10);
V_INDEX_ID PRIMARY_INDEX10.ID%TYPE;
V_ID_CARD PRIMARY_INDEX10.ID_CARD%TYPE;
CURSOR TEMP_CURSOR IS
SELECT T2.ID,PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區資料'
AND T2.REMARK = '**市****區資料';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得一行遊標資料並放到對應變數中 */
FETCH TEMP_CURSOR
INTO V_INDEX_ID,V_ID_CARD;
/* 如果沒有資料則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 業務邏輯 */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = V_INDEX_ID
WHERE ID_CARD = V_ID_CARD;
/* 更新一次,+1 */
V_COUNT := V_COUNT + 1;
/* 1000條提交1次 */
IF V_COUNT >= 1000 THEN
COMMIT; --提交
V_COUNT := 0; --重置
END IF;
END LOOP;
COMMIT; -- 提交所有資料,把這個去掉,可以檢視是否是自己想要的效果,再決定是否提交
CLOSE TEMP_CURSOR;
END;

  執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  10000條1提交,執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  方式四:顯式遊標+陣列(更新一次提交一次)(使用BULK COLLECT)

/* 使用遊標+陣列進行更新(更新一次提交一次) */
DECLARE
/* 建立陣列:一列多行 */
TYPE TYPE_INDEX_ID IS TABLE OF PRIMARY_INDEX10.ID%TYPE;
TYPE TYPE_ID_CARD IS TABLE OF PRIMARY_INDEX10.ID_CARD%TYPE;
/* 起別名 */
V_INDEX_ID TYPE_INDEX_ID;
V_ID_CARD TYPE_ID_CARD;
/* 將查詢出來的資料放到遊標裡 */
CURSOR TEMP_CURSOR IS
SELECT T2.ID,PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區資料'
AND T2.REMARK = '**市****區資料';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得1000行遊標資料並放到對應陣列中,每次讀取1000條資料 */
FETCH TEMP_CURSOR BULK COLLECT
INTO V_INDEX_ID,V_ID_CARD LIMIT 1000;
/* 如果沒有資料則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 遍歷資料 */
FOR I IN V_INDEX_ID.FIRST .. V_INDEX_ID.LAST LOOP
/* 業務邏輯 */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = V_INDEX_ID(I)
WHERE ID_CARD = V_ID_CARD(I);
COMMIT;
END LOOP;
END LOOP;
CLOSE TEMP_CURSOR;
END;

  執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  方式五:顯式遊標+陣列(1000條提交一次)(使用BULK COLLECT)

/* 使用遊標+陣列進行更新(1000條提交一次) */
DECLARE
/* 建立陣列:一列多行 */
TYPE TYPE_INDEX_ID IS TABLE OF PRIMARY_INDEX10.ID%TYPE;
TYPE TYPE_ID_CARD IS TABLE OF PRIMARY_INDEX10.ID_CARD%TYPE;
/* 起別名 */
V_INDEX_ID TYPE_INDEX_ID;
V_ID_CARD TYPE_ID_CARD;
/* 將查詢出來的資料放到遊標裡 */
CURSOR TEMP_CURSOR IS
SELECT T2.ID,PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區資料'
AND T2.REMARK = '**市****區資料';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得1000行遊標資料並放到對應陣列中 */
FETCH TEMP_CURSOR BULK COLLECT
INTO V_INDEX_ID,V_ID_CARD LIMIT 1000;
/* 如果沒有資料則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 遍歷資料 */
FOR I IN V_INDEX_ID.FIRST .. V_INDEX_ID.LAST LOOP --或者:FOR I IN 1 .. V_INDEX_ID.COUNT LOOP
/* 業務邏輯 */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = V_INDEX_ID(I)
WHERE ID_CARD = V_ID_CARD(I);
IF I >= V_INDEX_ID.LAST THEN
COMMIT; --提交
END IF;
END LOOP;
END LOOP;
CLOSE TEMP_CURSOR;
END;

  執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  方式六:推薦使用(使用BULK COLLECT和FORALL)

/* 使用遊標+陣列進行更新(BULK COLLECT和FORALL) */
DECLARE
/* 建立陣列:一列多行 */
TYPE TYPE_INDEX_ID IS TABLE OF PRIMARY_INDEX10.ID%TYPE;
TYPE TYPE_ID_CARD IS TABLE OF PRIMARY_INDEX10.ID_CARD%TYPE;
/* 起別名 */
V_INDEX_ID TYPE_INDEX_ID;
V_ID_CARD TYPE_ID_CARD;
/* 將查詢出來的資料放到遊標裡 */
CURSOR TEMP_CURSOR IS
SELECT T2.ID,V_ID_CARD LIMIT 1000;
/* 如果沒有資料則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 遍歷資料 */
FORALL I IN 1 .. V_INDEX_ID.COUNT-- 或者V_INDEX_ID.FIRST .. V_INDEX_ID.LAST
/* 業務邏輯 */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = V_INDEX_ID(I)
WHERE ID_CARD = V_ID_CARD(I);
COMMIT; --提交
END LOOP;
CLOSE TEMP_CURSOR;
END;

  執行時間:

Oracle使用遊標進行分批次更新資料的6種方式及速度比對

  從Oracle8開始,oracle為PL/SQL引入了兩個新的資料操縱語言(DML)語句:BULK COLLECT和FORALL。

  這兩個語句在PL/SQL內部進行一種陣列處理;BULK COLLECT提供對資料的高速檢索,FORALL可大大改進INSERT、UPDATE和DELETE操作的效能。

  Oracle資料庫使用這些語句大大減少了PL/SQL與SQL語句執行引擎的環境切換次數,從而使其效能有了顯著提高。

小結:

  資料量小的時候可以用方式二,資料量大的時候推薦使用方式六;

  一定要建索引。

以上就是Oracle使用遊標進行分批次更新的6種方式及速度比對的詳細內容,更多關於Oracle 遊標的資料請關注我們其它相關文章!