數據庫內部對象X$統計信息過舊,導致v$lock查詢慢
前段時間用python寫了個zabbix監控腳本,里面有一個檢查鎖的sql語句,sql語句是這樣子的
select count(*) retvalue from v$lock where type in('TM', 'TX') and ctime > 600;
但是zabbix界面顯示這條語句超時,zabbix超時時間默認是3s,我將其改為15s,竟然還是超時,看樣子要仔細研究這個sql語句了。
這一看不得了,這條語句執行用了18s,統計v$lock的行數竟然要7min之久,這明顯無法接受。
SQL> select count(*) retvalue from v$lock where type in('TM', 'TX') and ctime > 600; RETVALUE ---------- 0 Elapsed: 00:00:18.82
查看其執行計划
SQL> select * from table(dbms_xplan.display_cursor()); --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 (100)| | 1 | SORT AGGREGATE | | 1 | 53 | | |* 2 | HASH JOIN | | 1 | 53 | 0 (0)| | 3 | MERGE JOIN CARTESIAN | | 1 | 41 | 0 (0)| |* 4 | FIXED TABLE FULL | X$KSUSE | 1 | 19 | 0 (0)| | 5 | BUFFER SORT | | 1 | 22 | 0 (0)| |* 6 | FIXED TABLE FULL | X$KSQRS | 1 | 22 | 0 (0)| | 7 | VIEW | GV$_LOCK | 10 | 120 | 0 (0)| | 8 | UNION-ALL | | | | | |* 9 | FILTER | | | | | | 10 | VIEW | GV$_LOCK1 | 2 | 24 | 0 (0)| | 11 | UNION-ALL | | | | | |* 12 | FIXED TABLE FULL| X$KDNSSF | 1 | 77 | 0 (0)| |* 13 | FIXED TABLE FULL| X$KSQEQ | 1 | 77 | 0 (0)| |* 14 | FIXED TABLE FULL | X$KTADM | 1 | 77 | 0 (0)| |* 15 | FIXED TABLE FULL | X$KTATRFIL | 1 | 77 | 0 (0)| |* 16 | FIXED TABLE FULL | X$KTATRFSL | 1 | 77 | 0 (0)| |* 17 | FIXED TABLE FULL | X$KTATL | 1 | 77 | 0 (0)| |* 18 | FIXED TABLE FULL | X$KTSTUSC | 1 | 77 | 0 (0)| |* 19 | FIXED TABLE FULL | X$KTSTUSS | 1 | 77 | 0 (0)| |* 20 | FIXED TABLE FULL | X$KTSTUSG | 1 | 77 | 0 (0)| |* 21 | FIXED TABLE FULL | X$KTCXB | 1 | 77 | 0 (0)| --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("SADDR"="S"."ADDR" AND TO_CHAR(USERENV('INSTANCE'))||RAWTOHEX("RADDR")=TO_CHAR("R"."INST_ID")|| RAWTOHEX("R"."ADDR")) 4 - filter("S"."INST_ID"=USERENV('INSTANCE')) 6 - filter(("R"."KSQRSIDT"='TM' OR "R"."KSQRSIDT"='TX')) 9 - filter(USERENV('INSTANCE') IS NOT NULL)
統計v$lock的行數
SQL> select count(*) from v$lock; COUNT(*) ---------- 600 Elapsed: 00:07:46.84
這條語句的執行計划與上面的一樣,這里我就不貼出來了
v$lock只有600行,怎么會執行時間這么久,通過v$session能看到這條語句的等待事件為"direct path read temp"
該等待事件表示服務器進程直接讀取臨時表空間的數據,通常由臨時表太大造成。從上面的執行計划中可以看出臨時表很大的原因可能是"MERGE JOIN CARTESIAN"。
"MERGE JOIN CARTESIAN"表示笛卡爾聯接,如果兩表的行數都不小的話,這的確會造成臨時表過大。查看X$KSUSE,X$KSQRS的行數
SQL> select count(*) from X$KSUSE; COUNT(*) ---------- 4544 SQL> select count(*) from X$KSQRS; COUNT(*) ---------- 20224
這幾千和幾萬來個笛卡爾積就是幾千萬的臨時數據了,而我的pga只有4g,pga不夠所以就用到了臨時表空間進行表關聯,也就造成了等待事件,所以說這條語句慢的主因就是這個笛卡兒積。
這條語句之前執行都好好的,為什么現在慢了呢,最可能的情況是統計信息過舊,因為自動統計信息收集job不會收集固定對象也就是X$表的統計信息。
收集下固定對象的統計信息
SQL> begin dbms_stats.gather_fixed_objects_stats; end; / PL/SQL procedure successfully completed.
再執行以下語句,可以看到執行時間0.1s都不到,而且執行計划也恢復正常,趕緊在我這邊的生產庫把類似問題進行處理,嘿嘿。
SQL> select count(*) from v$lock; COUNT(*) ---------- 600 Elapsed: 00:00:00.08 SQL> select * from table(dbms_xplan.display_cursor()); --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 29 (100)| | | 1 | SORT AGGREGATE | | 1 | 36 | | | | 2 | HASH JOIN | | 3034 | 106K| 29 (100)| 00:00:01 | | 3 | HASH JOIN | | 15 | 360 | 23 (100)| 00:00:01 | | 4 | VIEW | GV$_LOCK | 15 | 180 | 22 (100)| 00:00:01 | | 5 | UNION-ALL | | | | | | | 6 | FILTER | | | | | | | 7 | VIEW | GV$_LOCK1 | 7 | 84 | 15 (100)| 00:00:01 | | 8 | UNION-ALL | | | | | | | 9 | FIXED TABLE FULL| X$KDNSSF | 1 | 16 | 1 (100)| 00:00:01 | | 10 | FIXED TABLE FULL| X$KSQEQ | 6 | 102 | 14 (100)| 00:00:01 | | 11 | FIXED TABLE FULL | X$KTADM | 1 | 20 | 5 (100)| 00:00:01 | | 12 | FIXED TABLE FULL | X$KTATRFIL | 1 | 14 | 0 (0)| | | 13 | FIXED TABLE FULL | X$KTATRFSL | 1 | 14 | 0 (0)| | | 14 | FIXED TABLE FULL | X$KTATL | 1 | 20 | 0 (0)| | | 15 | FIXED TABLE FULL | X$KTSTUSC | 1 | 14 | 0 (0)| | | 16 | FIXED TABLE FULL | X$KTSTUSS | 1 | 16 | 0 (0)| | | 17 | FIXED TABLE FULL | X$KTSTUSG | 1 | 14 | 0 (0)| | | 18 | FIXED TABLE FULL | X$KTCXB | 1 | 18 | 1 (100)| 00:00:01 | | 19 | FIXED TABLE FULL | X$KSUSE | 4544 | 54528 | 1 (100)| 00:00:01 | | 20 | FIXED TABLE FULL | X$KSQRS | 20224 | 237K| 5 (100)| 00:00:01 | ---------------------------------------------------------------------------------------
總結:
1.一些動態性能視圖v$查詢很慢的話,可能是由於動態性能視圖所查詢的內部對象表x$統計信息過舊,cbo選擇了錯誤的執行計划造成。
2.自動統計信息收集job不會收集內部對象表的統計信息,所以需要dba定時手工收集,或者是自己創建個job定期執行。