1.情景展示
一共有22w條數(shù)據(jù), 需要將A表的主鍵更新至B表的指定字段,如何快速完成更新?
2.解決方案
聲明:
解決方案不只一種,該文章只介紹快速游標(biāo)法及代碼實(shí)現(xiàn);
兩張表的ID和ID_CARD字段都建立了索引。
方式一:使用隱式游標(biāo)(更新一次提交1次)
--快速游標(biāo)法
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 = '**市****區(qū)數(shù)據(jù)'
AND T2.REMARK = '**市****區(qū)數(shù)據(jù)') LOOP
/* LOOP循環(huán)的是TEMP_CURSOR(逐條讀取TEMP_CURSOR) */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = TEMP_CURSOR.ID
WHERE ID_CARD = TEMP_CURSOR.ID_CARD;
COMMIT; --提交
END LOOP;
END;
執(zhí)行時(shí)間:
方式二:使用隱式游標(biāo)(更新1000次提交1次)(推薦使用)
/* 使用隱式游標(biāo)進(jìn)行分批次更新 */
DECLARE
V_COUNT NUMBER(10);
BEGIN
/* 隱式游標(biāo) */
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 = '**市****區(qū)數(shù)據(jù)'
AND T2.REMARK = '**市****區(qū)數(shù)據(jù)') LOOP
/* 業(yè)務(wù)邏輯 */
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; -- 提交所有數(shù)據(jù),把這個(gè)去掉,可以查看是否是自己想要的效果,再?zèng)Q定是否提交
END;
執(zhí)行時(shí)間:
方式三:顯式游標(biāo)+分批次更新(1000條1提交)
/* 使用游標(biāo)進(jìn)行分批次更新 */
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, T2.ID_CARD
FROM VIRTUAL_CARD10 T1, PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區(qū)數(shù)據(jù)'
AND T2.REMARK = '**市****區(qū)數(shù)據(jù)';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得一行游標(biāo)數(shù)據(jù)并放到對(duì)應(yīng)變量中 */
FETCH TEMP_CURSOR
INTO V_INDEX_ID, V_ID_CARD;
/* 如果沒有數(shù)據(jù)則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 業(yè)務(wù)邏輯 */
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; -- 提交所有數(shù)據(jù),把這個(gè)去掉,可以查看是否是自己想要的效果,再?zèng)Q定是否提交
CLOSE TEMP_CURSOR;
END;
執(zhí)行時(shí)間:
10000條1提交,執(zhí)行時(shí)間:
方式四:顯式游標(biāo)+數(shù)組(更新一次提交一次)(使用BULK COLLECT)
/* 使用游標(biāo)+數(shù)組進(jìn)行更新(更新一次提交一次) */
DECLARE
/* 創(chuàng)建數(shù)組:一列多行 */
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;
/* 將查詢出來的數(shù)據(jù)放到游標(biāo)里 */
CURSOR TEMP_CURSOR IS
SELECT T2.ID, T2.ID_CARD
FROM VIRTUAL_CARD10 T1, PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區(qū)數(shù)據(jù)'
AND T2.REMARK = '**市****區(qū)數(shù)據(jù)';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得1000行游標(biāo)數(shù)據(jù)并放到對(duì)應(yīng)數(shù)組中,每次讀取1000條數(shù)據(jù) */
FETCH TEMP_CURSOR BULK COLLECT
INTO V_INDEX_ID, V_ID_CARD LIMIT 1000;
/* 如果沒有數(shù)據(jù)則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 遍歷數(shù)據(jù) */
FOR I IN V_INDEX_ID.FIRST .. V_INDEX_ID.LAST LOOP
/* 業(yè)務(wù)邏輯 */
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;
執(zhí)行時(shí)間:
方式五: 顯式游標(biāo)+數(shù)組(1000條提交一次)(使用BULK COLLECT)
/* 使用游標(biāo)+數(shù)組進(jìn)行更新(1000條提交一次) */
DECLARE
/* 創(chuàng)建數(shù)組:一列多行 */
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;
/* 將查詢出來的數(shù)據(jù)放到游標(biāo)里 */
CURSOR TEMP_CURSOR IS
SELECT T2.ID, T2.ID_CARD
FROM VIRTUAL_CARD10 T1, PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區(qū)數(shù)據(jù)'
AND T2.REMARK = '**市****區(qū)數(shù)據(jù)';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得1000行游標(biāo)數(shù)據(jù)并放到對(duì)應(yīng)數(shù)組中 */
FETCH TEMP_CURSOR BULK COLLECT
INTO V_INDEX_ID, V_ID_CARD LIMIT 1000;
/* 如果沒有數(shù)據(jù)則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 遍歷數(shù)據(jù) */
FOR I IN V_INDEX_ID.FIRST .. V_INDEX_ID.LAST LOOP --或者:FOR I IN 1 .. V_INDEX_ID.COUNT LOOP
/* 業(yè)務(wù)邏輯 */
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;
執(zhí)行時(shí)間:
方式六:推薦使用(使用BULK COLLECT和FORALL)
/* 使用游標(biāo)+數(shù)組進(jìn)行更新(BULK COLLECT和FORALL) */
DECLARE
/* 創(chuàng)建數(shù)組:一列多行 */
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;
/* 將查詢出來的數(shù)據(jù)放到游標(biāo)里 */
CURSOR TEMP_CURSOR IS
SELECT T2.ID, T2.ID_CARD
FROM VIRTUAL_CARD10 T1, PRIMARY_INDEX10 T2
WHERE T1.ID_CARD = T2.ID_CARD
AND T1.REMARK = '**市****區(qū)數(shù)據(jù)'
AND T2.REMARK = '**市****區(qū)數(shù)據(jù)';
BEGIN
OPEN TEMP_CURSOR;
LOOP
/* 取得1000行游標(biāo)數(shù)據(jù)并放到對(duì)應(yīng)數(shù)組中 */
FETCH TEMP_CURSOR BULK COLLECT
INTO V_INDEX_ID, V_ID_CARD LIMIT 1000;
/* 如果沒有數(shù)據(jù)則退出 */
EXIT WHEN TEMP_CURSOR%NOTFOUND;
/* 遍歷數(shù)據(jù) */
FORALL I IN 1 .. V_INDEX_ID.COUNT-- 或者V_INDEX_ID.FIRST .. V_INDEX_ID.LAST
/* 業(yè)務(wù)邏輯 */
UPDATE VIRTUAL_CARD10
SET INDEX_ID = V_INDEX_ID(I)
WHERE ID_CARD = V_ID_CARD(I);
COMMIT; --提交
END LOOP;
CLOSE TEMP_CURSOR;
END;
執(zhí)行時(shí)間:
從Oracle8開始,oracle為PL/SQL引入了兩個(gè)新的數(shù)據(jù)操縱語言(DML)語句:BULK COLLECT和FORALL。
這兩個(gè)語句在PL/SQL內(nèi)部進(jìn)行一種數(shù)組處理;BULK COLLECT提供對(duì)數(shù)據(jù)的高速檢索,F(xiàn)ORALL可大大改進(jìn)INSERT、UPDATE和DELETE操作的性能。
Oracle數(shù)據(jù)庫(kù)使用這些語句大大減少了PL/SQL與SQL語句執(zhí)行引擎的環(huán)境切換次數(shù),從而使其性能有了顯著提高。
小結(jié):
數(shù)據(jù)量小的時(shí)候可以用方式二,數(shù)據(jù)量大的時(shí)候推薦使用方式六;
一定要建索引。
以上就是Oracle使用游標(biāo)進(jìn)行分批次更新的6種方式及速度比對(duì)的詳細(xì)內(nèi)容,更多關(guān)于Oracle 游標(biāo)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- Oracle 遍歷游標(biāo)的四種方式匯總(for、fetch、while、BULK COLLECT)
- Oracle數(shù)據(jù)庫(kù)游標(biāo)連接超出解決方案
- 詳解Oracle游標(biāo)的簡(jiǎn)易用法
- Oracle游標(biāo)的使用實(shí)例詳解
- Oracle中游標(biāo)Cursor基本用法詳解
- 詳解Oracle隱式游標(biāo)和顯式游標(biāo)
- Oracle存儲(chǔ)過程游標(biāo)用法分析
- Oracle出現(xiàn)超出打開游標(biāo)最大數(shù)的解決方法
- Oracle顯示游標(biāo)的使用及游標(biāo)for循環(huán)
- Oracle存儲(chǔ)過程返回游標(biāo)實(shí)例詳解
- Oracle 游標(biāo)使用總結(jié)