批量插入 Oracle 數據庫:哪個更好:FOR 游標循環還是簡單的選擇? (Bulk Insert into Oracle database: Which is better: FOR Cursor loop or a simple Select?)


問題描述

批量插入 Oracle 數據庫:哪個更好:FOR 游標循環還是簡單的選擇? (Bulk Insert into Oracle database: Which is better: FOR Cursor loop or a simple Select?)

Which would be a better option for bulk insert into an Oracle database ?  A FOR Cursor loop like

DECLARE
   CURSOR C1 IS SELECT * FROM FOO;
BEGIN
   FOR C1_REC IN C1 LOOP
   INSERT INTO BAR(A,
                B,
                C)
          VALUES(C1.A,
                 C1.B,
                 C1.C);
   END LOOP;
END

or a simple select, like:

INSERT INTO BAR(A,
                B,
                C)
        (SELECT A,
                B,
                C
        FROM FOO);

Any specific reason either one would be better ?


參考解法

方法 1:

I would recommend the Select option because cursors take longer. Also using the Select is much easier to understand for anyone who has to modify your query

方法 2:

The general rule-of-thumb is, if you can do it using a single SQL statement instead of using PL/SQL, you should. It will usually be more efficient.

However, if you need to add more procedural logic (for some reason), you might need to use PL/SQL, but you should use bulk operations instead of row-by-row processing. (Note: in Oracle 10g and later, your FOR loop will automatically use BULK COLLECT to fetch 100 rows at a time; however your insert statement will still be done row-by-row).

e.g.

DECLARE
   TYPE tA IS TABLE OF FOO.A%TYPE INDEX BY PLS_INTEGER;
   TYPE tB IS TABLE OF FOO.B%TYPE INDEX BY PLS_INTEGER;
   TYPE tC IS TABLE OF FOO.C%TYPE INDEX BY PLS_INTEGER;
   rA tA;
   rB tB;
   rC tC;
BEGIN
   SELECT * BULK COLLECT INTO rA, rB, rC FROM FOO;
   -- (do some procedural logic on the data?)
   FORALL i IN rA.FIRST..rA.LAST
      INSERT INTO BAR(A,
                      B,
                      C)
      VALUES(rA(i),
             rB(i),
             rC(i));
END;

The above has the benefit of minimising context switches between SQL and PL/SQL. Oracle 11g also has better support for tables of records so that you don't have to have a separate PL/SQL table for each column.

Also, if the volume of data is very great, it is possible to change the code to process the data in batches.

方法 3:

If your rollback segment/undo segment can accomodate the size of the transaction then option 2 is better.  Option 1 is useful if you do not have the rollback capacity needed and have to break the large insert into smaller commits so you don't get rollback/undo segment too small errors.  

方法 4:

A simple insert/select like your 2nd option is far preferable.  For each insert in the 1st option you require a context switch from pl/sql to sql.  Run each with trace/tkprof and examine the results.

If, as Michael mentions, your rollback cannot handle the statement then have your dba give you more.  Disk is cheap, while partial results that come from inserting your data in multiple passes is potentially quite expensive.  (There is almost no undo associated with an insert.)

方法 5:

I think that in this question is missing one important information.

How many records will you insert?

  1. If from 1 to cca. 10.000 then you should use SQL statement (Like they said it is easy to understand and it is easy to write).
  2. If from cca. 10.000 to cca. 100.000 then you should use cursor, but you should add logic to commit on every 10.000 records. 
  3. If from cca. 100.000 to millions then you should use bulk collect for better performance.

(by Sathyajith BhatJosh MeinJeffrey KempMichaelNScott Swanksulica)

參考文件

  1. Bulk Insert into Oracle database: Which is better: FOR Cursor loop or a simple Select? (CC BY-SA 3.0/4.0)

#plsql #SQL #oracle






相關問題

RAISE_APPLICATION_ERROR 不返回消息 (RAISE_APPLICATION_ERROR doesn't return the message)

PL/SQL 塊和循環練習 (PL/SQL block and LOOP exercise)

如何從列中僅提取編號的行 (How to extract only numbered rows from a column)

如何編寫一個程序來自動執行一組查詢 (How to write a procedure to execute set of queries automatically)

使用 DBMS_OUTPUT.put_line 顯示錯誤消息 (Display error message using DBMS_OUTPUT.put_line)

如何編寫將Oracle數據庫表數據導出到excel文件的程序 (How to write a Procedure which exports Oracle database table data into excel file)

如何重載對像類型中的方法 (How to overload a method in an object type)

有沒有辦法以編程方式從 Oracle 包中提取表引用? (Is there a way to programmatically extract table references from an Oracle package?)

批量插入 Oracle 數據庫:哪個更好:FOR 游標循環還是簡單的選擇? (Bulk Insert into Oracle database: Which is better: FOR Cursor loop or a simple Select?)

如何使用參數“foo 表”執行 SP? (How to execute SP with arguments 'table of foo'?)

PL/SQL 我做錯了什麼? (PL/SQL What am I doing wrong?)

PL/SQL 顯示帶有條件的表中的數據 (PL/SQL Display Data From a Table with a Condition)







留言討論