SQL Trace 與 10046 事件是診斷 Oracle 效能問題的利器。Level 12 (含等待事件與綁定變數) 能提供:
實戰發現:在 Session 已開啟 SQL Trace 狀態下執行 SQL,會強制重新解析。因綁定變數窺視 導致生成新的 Child Cursor,執行計畫可能與無 Trace 時截然不同,進而誤導分析判斷。此問題存在於 9i、10g,11g 待驗證。
CREATE TABLE t1 (value NUMBER, flag NUMBER, pad VARCHAR2(2000));
INSERT INTO t1 SELECT rownum, MOD(rownum,2000), LPAD('x',1000,'x') FROM dba_objects; -- 49,796 筆,flag 0-1999 各約 25 筆
INSERT INTO t1 SELECT rownum, 3000, LPAD('x',1000,'x') FROM dba_objects WHERE rownum <= 10000; -- flag=3000 有 10,000 筆
COMMIT;
CREATE INDEX t1_idx ON t1(flag);
EXEC dbms_stats.gather_table_stats(ownname=>USER, tabname=>'T1', cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS');
-- FLAG 欄位收集到 75 個 Bucket 的直方圖
首次執行綁定 :v_flag=3000 (高頻值),Oracle 窺視並生成 Child Cursor 0,選擇 Full Table Scan (Cost 765)。後續執行 :v_flag=300/500 (低頻值) 仍複用 Cursor 0,維持全表掃描,邏輯讀 8,575,雖然走 Index Range Scan 只要 27 邏輯讀卻未被選擇。
EXEC sys.dbms_system.set_ev(sid, serial#, 10046, 12, '');
再次執行 :v_flag=410 (低頻值),Trace 顯示 PARSE #1 ... mis=1 (硬解析),執行計畫轉為 INDEX RANGE SCAN,邏輯讀驟降至 27。V$SQL 出現 Child Number 1,Plan Hash Value 變更。
SELECT * FROM v$sql_shared_cursor WHERE sql_id='8hdvb5nwfqm8r';
結果顯示 STATS_ROW_MISMATCH = Y,官方文件解釋:「現有統計資訊與現有 Child Cursor 不符」。開啟 Trace 導致優化器環境變更 (統計層面),觸發硬解析並重新窺視綁定值,產生最優新計畫。
DBMS_XPLAN.DISPLAY_CURSOR 觀察現有 Child Cursor 計畫,或用 OPTIMIZER_USE_SQL_PLAN_BASELINES / ADAPTIVE_CURSOR_SHARING (11g+) 穩定計畫,而非盲目依賴 Trace。DBMS_MONITOR.SESSION_TRACE_ENABLE 行為一致。