執行計劃中Row 數量為0

adian發表於2007-06-14
執行計劃中數量為0?[@more@]從Metalink中找到答案
如果遊標沒有關閉,那麼透過TKPROF生成的輸出將不會包含精確的執行計劃,在原始的trace檔案中要麼沒有STAT行,或則行數量遺失。當然可以透過EXPLAIN選項來產生執行計劃,但這個時候產生的執行計劃不一定是正確的。如果遊標關閉,STAT行寫入原始的trace檔案。

解決方法:
可以透過執行其他無關的SQL來關閉遊標或透過dbms_session.reset_package過程來完成。

驗證方法:對比兩種不同方式,檢查在遊標關閉和非關閉兩種情況下,是否生成了對應的執行計劃。

驗證過程:

1. 建立一個過程,在過程中開啟一個遊標,執行某些操作,然後關閉遊標。
建立表:

SQL> desc t_plan;
 Name                                      Null?    Type
 ----------------------------------------- -------- --------------------

 OWNER                                     NOT NULL VARCHAR2(30)
 OBJECT_NAME                               NOT NULL VARCHAR2(30)

建立過程:
CREATE OR REPLACE PROCEDURE scott.tkprof_test
AS
   counts    NUMBER;

   CURSOR c1
   IS
      SELECT   COUNT (*)
          FROM t_plan
      GROUP BY owner;
BEGIN
   OPEN c1;

   LOOP
      FETCH c1
       INTO counts;
      EXIT WHEN c1%NOTFOUND;
      DBMS_OUTPUT.put_line ('counts:' || counts);
   END LOOP;

   CLOSE c1;
END;

2. 登入SQL*PLUS,開啟一個session,設定SQL_TRACE為true,執行步驟1中建立的過程,不執行reset_package過程,設定SQL_TRACE為false。
SQL> alter session set sql_trace=true;

Session altered.

SQL> exec tkprof_test;
counts:99

PL/SQL procedure successfully completed.

SQL> alter session set sql_trace=false;

Session altered.

3. 透過TKPROF命令,檢查步驟2輸出檔案。
********************************************************************************

SELECT   COUNT (*)
          FROM t_plan
      GROUP BY owner

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

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 59     (recursive depth: 1)
********************************************************************************

4. 登入SQL*PLUS,開啟一個session,設定SQL_TRACE為true,執行步驟1中建立的過程,執行reset_package過程,設定SQL_TRACE為false。
SQL> alter session set sql_trace=true;

Session altered.

SQL> exec tkprof_test;
counts:99

PL/SQL procedure successfully completed.

SQL> exec dbms_session.reset_package;

PL/SQL procedure successfully completed.

SQL> alter session set sql_trace=false;

Session altered.

5. 透過TKPROF命令,檢查步驟4輸出檔案。
********************************************************************************

SELECT   COUNT (*)
          FROM t_plan
      GROUP BY owner

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

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 59     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT GROUP BY 
     99   TABLE ACCESS FULL T_PLAN 

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

注意:
1. 執行reset_package必須在alter session set sql_tracle = false命令之前執行,否則同樣不能得到執行計劃。
2. 對於單個在SQL*PLUS中執行的語句,執行完成後,可以透過“Select * from dual”或者“alter session set sql_tracle = ture”,遊標會立刻關閉。
3. 今天讀到Tom的《Oracle Expert one by one》10章的時候,提到透過原始的trace檔案判斷是否已經生成可信任的執行計劃。在原始的trace檔案中,STAT行紀錄了執行時精確的執行計劃,同時也會包含每一步執行計劃中關聯的正確的記錄行數。也提到了只有當相關遊標關閉之後,才會產生相關紀錄。回過頭看一下上面關閉遊標的例子,其生成的trace檔案相關部分內容為:
=====================
PARSING IN CURSOR #2 len=61 dep=1 uid=59 oct=3 lid=59 tim=19288630504 hv=2097396184 ad='66c8c0a4'

SELECT   COUNT (*)
          FROM t_plan
      GROUP BY owner

END OF STMT
PARSE #2:c=0,e=38470,p=0,cr=2,cu=0,mis=0,r=0,dep=1,og=4,tim=19288630498
EXEC #2:c=0,e=50,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=19288660693
FETCH #2:c=15625,e=170,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=19288665392
FETCH #2:c=0,e=17,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=19288670162
EXEC #1:c=15625,e=83199,p=0,cr=6,cu=0,mis=0,r=1,dep=0,og=4,tim=19288675090
=====================
PARSING IN CURSOR #3 len=52 dep=0 uid=59 oct=47 lid=59 tim=19288679793 hv=1697159799 ad='66c61e20'
BEGIN DBMS_OUTPUT.GET_LINES(:LINES, :NUMLINES); END;
END OF STMT
PARSE #3:c=0,e=108,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19288679789
EXEC #3:c=0,e=209,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=4,tim=19288702763
*** 2007-06-13 14:35:20.000
=====================
PARSING IN CURSOR #1 len=40 dep=0 uid=59 oct=47 lid=59 tim=19313599313 hv=1443640743 ad='66b81f64'

BEGIN dbms_session.reset_package; END;

END OF STMT
PARSE #1:c=0,e=342,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19313599304

STAT #2 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT GROUP BY '
STAT #2 id=2 cnt=99 pid=1 pos=1 obj=30711 op='TABLE ACCESS FULL T_PLAN '

EXEC #1:c=0,e=21520,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=4,tim=19313684039
=====================

已經將相關部分highlight,可以看到當查詢的SELECT COUNT (*) FROM t_plan GROUP BY owner; 執行完成之後,並沒有生成STAT紀錄。直到呼叫dbms_session.reset_package方法之後,生成了STAT相關紀錄。從STAT的記錄行,可以看到操作以及對應的行數。

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

相關文章