FORALL執行UPDATE語句(二)

yangtingkun發表於2011-06-24

ITPUB上看到一個FORALL執行UPDATE的帖子,覺得有點意思,簡單記錄一下。

這一篇分析UPDATEFORALLINSERTDELETE語句實現上不同的根源。

原帖地址:http://www.itpub.net/thread-1443896-1-1.html

FOR ALL語法淺析:http://yangtingkun.itpub.net/post/468/198828

FORALL執行UPDATE語句:http://yangtingkun.itpub.net/post/468/518933

FORALL執行DELETE語句:http://yangtingkun.itpub.net/post/468/519691

 

 

在前面的測試中發現UPDATE語句很特別,INSERTDELETE語句都使用的是陣列繫結,一次執行,而UPDATE語句則執行了多次。

導致UPDATE語句特殊的原因是在沒有指定WHERE語句中條件的情況下,設定了SET語句中的繫結,造成了對於SET語句中陣列繫結的每個值,UPDATE都要執行一次。

而語句的處理上,實際上UPDATEINSERTDELETE沒有什麼區別,仍然採用的是陣列繫結一次執行的方式。下面給出了幾種不同情況的UPDATE語句,簡單分析一下:

SQL> CREATE TABLE T AS
2 SELECT ROWNUM ID, TNAME NAME FROM TAB;

表已建立。

SQL> EXEC DBMS_SESSION.SESSION_TRACE_ENABLE

PL/SQL 過程已成功完成。

SQL> DECLARE
2 TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 V_ID T_ID;
4 BEGIN
5 SELECT ID
6 BULK COLLECT INTO V_ID
7 FROM T;
8 FORALL I IN V_ID.FIRST..V_ID.LAST
9 UPDATE T
10 SET NAME = LOWER(NAME)
11 WHERE ID = V_ID(I);
12 END;
13 /

PL/SQL 過程已成功完成。

SQL> DECLARE
2 TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 V_ID T_ID;
4 TYPE T_NAME IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
5 V_NAME T_NAME;
6 BEGIN
7 SELECT ID, NAME
8 BULK COLLECT INTO V_ID, V_NAME
9 FROM T;
10 FORALL I IN V_ID.FIRST..V_ID.LAST
11 UPDATE T
12 SET NAME = LOWER(V_NAME(I))
13 WHERE ID = V_ID(I);
14 END;
15 /

PL/SQL 過程已成功完成。

SQL> DECLARE
2 TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 V_ID T_ID;
4 TYPE T_NAME IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
5 V_NAME T_NAME;
6 BEGIN
7 SELECT ID, NAME
8 BULK COLLECT INTO V_ID, V_NAME
9 FROM T;
10 FORALL I IN V_NAME.FIRST..V_NAME.LAST
11 UPDATE T
12 SET NAME = LOWER(V_NAME(I));
13 END;
14 /

PL/SQL 過程已成功完成。

SQL> EXEC DBMS_SESSION.SESSION_TRACE_DISABLE

PL/SQL 過程已成功完成。

SQL> SELECT SPID
2 FROM V$PROCESS P, V$SESSION S
3 WHERE P.ADDR = S.PADDR
4 AND SID = USERENV('SID');

SPID
------------------------
4396

下面利用tkprof來分析trace檔案:

E:\>cd E:\oracle\diag\rdbms\test112\test112\trace

E:\oracle\diag\rdbms\test112\test112\trace>tkprof test112_ora_4396.trc output.txt sys=no

TKPROF: Release 11.2.0.1.0 - Development on 星期六 6 25 00:11:47 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

檢查格式化後的trace

TKPROF: Release 11.2.0.1.0 - Development on 星期六 6 25 00:11:47 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Trace file: test112_ora_4396.trc
Sort options: default

********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************

.
.
.
********************************************************************************

DECLARE
 TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
 V_ID T_ID;
BEGIN
 SELECT ID
 BULK COLLECT INTO V_ID
 FROM T;
 FORALL I IN V_ID.FIRST..V_ID.LAST
  UPDATE T
  SET NAME = LOWER(NAME)
  WHERE ID = V_ID(I);
END;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.07          0          0          0           0
Execute      1      0.00       0.00          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.01       0.07          0          0          0           1

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61 

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  SQL*Net message from client                     1        8.20          8.20
********************************************************************************
.
.
.
********************************************************************************

SQL ID: 92td25bnxfh1y
Plan Hash: 931696821
UPDATE T SET NAME = LOWER(NAME)
WHERE
 ID = :B1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.01          0         22          9           7
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.01          0         22          9           7

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T (cr=21 pr=0 pw=0 time=0 us)
      7   TABLE ACCESS FULL T (cr=21 pr=0 pw=0 time=0 us cost=3 size=30 card=1)

********************************************************************************

.
.
.
********************************************************************************

DECLARE
 TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
 V_ID T_ID;
 TYPE T_NAME IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
 V_NAME T_NAME;
BEGIN
 SELECT ID, NAME
 BULK COLLECT INTO V_ID, V_NAME
 FROM T;
 FORALL I IN V_ID.FIRST..V_ID.LAST
  UPDATE T
  SET NAME = LOWER(V_NAME(I))
  WHERE ID = V_ID(I);
END;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0          0          0           1

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61 

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  SQL*Net message from client                     1        8.21          8.21
********************************************************************************

.
.
.
********************************************************************************

SQL ID: c74pvwv4an74r
Plan Hash: 931696821
UPDATE T SET NAME = LOWER(:B1 )
WHERE
 ID = :B2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0         22          7           7
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0         22          7           7

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T (cr=21 pr=0 pw=0 time=0 us)
      7   TABLE ACCESS FULL T (cr=21 pr=0 pw=0 time=0 us cost=3 size=30 card=1)

********************************************************************************

DECLARE
 TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
 V_ID T_ID;
 TYPE T_NAME IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
 V_NAME T_NAME;
BEGIN
 SELECT ID, NAME
 BULK COLLECT INTO V_ID, V_NAME
 FROM T;
 FORALL I IN V_NAME.FIRST..V_NAME.LAST
  UPDATE T
  SET NAME = LOWER(V_NAME(I));
END;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0          0          0           1

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61 

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       2        0.00          0.00
  SQL*Net message from client                     2        9.42         16.16
  SQL*Net break/reset to client                   2        0.00          0.00
********************************************************************************

SQL ID: 0x6ddr8akzrjt
Plan Hash: 931696821
UPDATE T SET NAME = LOWER(:B1 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.01          0         22         36          49
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.01          0         22         36          49

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T (cr=21 pr=0 pw=0 time=0 us)
     49   TABLE ACCESS FULL T (cr=21 pr=0 pw=0 time=96 us cost=3 size=119 card=7)

********************************************************************************

.
.
.

可以看到,本質上UPDATEINSERTDELETE沒有區別,只是由於缺少WHERE語句的UPDATE語句在陣列繫結的時候構成了類似笛卡爾積的更新模式,而事實上這個SQL本身就是錯誤的。

上一篇得到的結論是由於使用觸發器的方式只能看到現象,而實際的執行次數,只能透過TRACE的方式來獲取。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-700713/,如需轉載,請註明出處,否則將追究法律責任。

相關文章