收集統計資訊
問題測試:
獲取自動收集統計資訊JOB的資訊
1* select log_id,log_date,owner,job_name,status,req_start_date,actual_start_date,run_duration,cpu_used from dba_scheduler_job_run_details where lower(job_name) like '%gather_stats_job%' order by log_id
LOG_ID LOG_DATE OWNER JOB_NAME STATUS ACTUAL_START_DATE RUN_DURATION CPU_USED
------ ----------------------------------- ----- ------------------------- ---------- ------------------------------ ------------------------- -------------------------
436 2014-07-31 22:55:17.477559 SYS GATHER_STATS_JOB SUCCEEDED 2014-07-31 22:54:53.775509 +000 00:00:24 +000 00:00:05.31
451 2014-08-02 09:33:01.565868 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-02 09:32:15.493005 +000 00:00:46 +000 00:00:11.20
493 2014-08-05 02:46:53.737519 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-05 02:46:18.885318 +000 00:00:35 +000 00:00:07.18
515 2014-08-07 04:28:10.499073 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-07 04:27:39.841948 +000 00:00:31 +000 00:00:08.03
534 2014-08-09 10:30:31.265575 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-09 10:29:27.029581 +000 00:01:04 +000 00:00:07.35
570 2014-08-11 22:20:18.896573 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-11 22:19:29.831058 +000 00:00:49 +000 00:00:08.36
602 2014-08-12 23:18:26.573014 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-12 23:17:49.866337 +000 00:00:37 +000 00:00:08.41
633 2014-08-13 22:17:33.236311 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-13 22:16:49.790815 +000 00:00:43 +000 00:00:09.04
657 2014-08-15 02:32:11.726540 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-15 02:31:35.913797 +000 00:00:36 +000 00:00:10.00
685 2014-08-19 02:49:17.709531 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-19 02:46:58.042017 +000 00:02:20 +000 00:00:37.87
715 2014-08-21 01:48:24.366631 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-21 01:45:49.330810 +000 00:02:35 +000 00:00:19.26
LOG_ID LOG_DATE OWNER JOB_NAME STATUS ACTUAL_START_DATE RUN_DURATION CPU_USED
------ ----------------------------------- ----- ------------------------- ---------- ------------------------------ ------------------------- -------------------------
725 2014-08-24 23:27:47.297346 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-24 23:27:21.684993 +000 00:00:26 +000 00:00:05.28
12 rows selected.
dbms_scheduler.run_job官方註解
RUN_JOB Procedure
This procedure runs a job immediately.
Syntax
DBMS_SCHEDULER.RUN_JOB (
job_name IN VARCHAR2,
use_current_session IN BOOLEAN DEFAULT TRUE);
Parameters
Table 93-48 RUN_JOB Procedure Parameters
Parameter
|
Description
|
job_name
|
The name of the job being run
|
use_current_session
|
This specifies whether the job run should occur in the same session as the one that the procedure was invoked from.
When use_current_session is set to TRUE:
-
You can test a job and see any possible errors on the command line.
-
run_count, last_start_date, last_run_duration, and failure_count are not updated.
-
RUN_JOB can be run in parallel with a regularly scheduled job run.
When use_current_session is set to FALSE:
-
You need to check the job log to find error information.
-
run_count, last_start_date, last_run_duration, and failure_count are updated.
-
RUN_JOB fails if a regularly scheduled job is running.
|
Usage Notes
The job does not have to be enabled. If the job is disabled, the following validity checks are performed before running it:
-
The job points to a valid job class.The job owner has EXECUTE privileges on the job class.If a program or chain is referenced, the program/chain exists.If a program or chain is referenced, the job owner has privileges to execute the program/chain.All argument values have been set (or have defaults).The job owner has the CREATE EXTERNAL JOB privilege if this is an external job.
The job can be run in two different modes. One is in the current user session. In this case, the call to RUN_JOB will block until it has completed the job. Any errors that occur during the execution of the job will be returned as errors to the RUN_JOB procedure. The other option is to run the job immediately like a regular job. In this case, RUN_JOB returns immediately and the job will be picked up by the coordinator and passed on to a job slave for execution. The Scheduler views and logs must be queried for the outcome of the job.
Multiple user sessions can use RUN_JOB in their sessions simultaneously when use_current_session is set to TRUE.
When using RUN_JOB with jobs that point to chains, use_current_session must be FALSE.
RUN_JOB requires that you be the owner of the job or have ALTER privileges on that job. You can also run a job if you have the CREATE ANY JOB privilege.
|
手工呼叫自動收集統計資訊job
SQL> exec dbms_scheduler.run_job('GATHER_STATS_JOB',true);
PL/SQL procedure successfully completed.
再次檢視自動收集統計資訊資訊
SQL> col job_name for a25
SQL> alter session set nls_timestamp_tz_format='yyyy-mm-dd hh24:mi:ss.ff';
Session altered.
SQL> select log_id,log_date,owner,job_name,status,req_start_date,actual_start_date,run_duration,cpu_used from dba_scheduler_job_run_details where lower(job_name) like '%gather_stats_job%' order by log_id;
LOG_ID LOG_DATE OWNER JOB_NAME STATUS ACTUAL_START_DATE RUN_DURATION CPU_USED
------ ----------------------------------- ----- ------------------------- ---------- ------------------------------ ------------------------- -------------------------
436 2014-07-31 22:55:17.477559 SYS GATHER_STATS_JOB SUCCEEDED 2014-07-31 22:54:53.775509 +000 00:00:24 +000 00:00:05.31
451 2014-08-02 09:33:01.565868 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-02 09:32:15.493005 +000 00:00:46 +000 00:00:11.20
493 2014-08-05 02:46:53.737519 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-05 02:46:18.885318 +000 00:00:35 +000 00:00:07.18
515 2014-08-07 04:28:10.499073 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-07 04:27:39.841948 +000 00:00:31 +000 00:00:08.03
534 2014-08-09 10:30:31.265575 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-09 10:29:27.029581 +000 00:01:04 +000 00:00:07.35
570 2014-08-11 22:20:18.896573 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-11 22:19:29.831058 +000 00:00:49 +000 00:00:08.36
602 2014-08-12 23:18:26.573014 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-12 23:17:49.866337 +000 00:00:37 +000 00:00:08.41
633 2014-08-13 22:17:33.236311 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-13 22:16:49.790815 +000 00:00:43 +000 00:00:09.04
657 2014-08-15 02:32:11.726540 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-15 02:31:35.913797 +000 00:00:36 +000 00:00:10.00
685 2014-08-19 02:49:17.709531 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-19 02:46:58.042017 +000 00:02:20 +000 00:00:37.87
715 2014-08-21 01:48:24.366631 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-21 01:45:49.330810 +000 00:02:35 +000 00:00:19.26
LOG_ID LOG_DATE OWNER JOB_NAME STATUS ACTUAL_START_DATE RUN_DURATION CPU_USED
------ ----------------------------------- ----- ------------------------- ---------- ------------------------------ ------------------------- -------------------------
725 2014-08-24 23:27:47.297346 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-24 23:27:21.684993 +000 00:00:26 +000 00:00:05.28
751 2014-08-27 04:58:12.980583 SYS GATHER_STATS_JOB SUCCEEDED 2014-08-27 04:57:51.591701 +000 00:00:21 +000 00:00:08.08
13 rows selected.
建立測試表
[ora10g@seconary ~]$ sqlplus tbs_11204/system
SQL*Plus: Release 10.2.0.5.0 - Production on Wed Aug 27 05:15:55 2014
Copyright (c) 1982, 2010, Oracle. All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> create table t_stat(a int,b int);
Table created.
插入資料
SQL> insert into t_stat select level,level from dual connect by level<=1000;
1000 rows created.
SQL> commit;
Commit complete.
確認沒有收集統計資訊
SQL> set linesize 300
SQL> select table_name,num_rows,blocks,degree,avg_row_len,chain_cnt from user_tables where lower(table_name)='t_stat';
TABLE_NAME NUM_ROWS BLOCKS DEGREE AVG_ROW_LEN CHAIN_CNT
------------------------------ ---------- ---------- ---------- ----------- ----------
T_STAT 1
SQL>
手工執行上述自動收集統計資訊的job
SQL> exec dbms_scheduler.run_job('GATHER_STATS_JOB',true);
PL/SQL procedure successfully completed.
再次檢視上述表已收集了統計資訊
SQL> select table_name,num_rows,blocks,degree,avg_row_len,chain_cnt from user_tables where lower(table_name)='t_stat';
TABLE_NAME NUM_ROWS BLOCKS DEGREE AVG_ROW_LEN CHAIN_CNT
------------------------------ ---------- ---------- ---------- ----------- ----------
T_STAT 1000 5 1 7 0
再回到開始的問題,從上述測試來看,可能原因就是tmp字首的表剛好在自動統計資訊收集完時間視窗外進行DML操作,所以沒有統計資訊
進一步分析,如果作過資料庫開發的人,可能會猜測這種TMP字首的表多用於儲存過程之中,用於臨時儲存儲存過程中間加工的結果,
可以透過如下指令碼獲取tmp字首的表是否位於儲存過程中
select owner,name from dba_source where lower(text) like '%tmp字首的表%';
如果位於儲存過程,儲存過程是否定時執行呢,如果是這樣的話,有種可能就是每次執行時tmp字首的表在儲存過程執行完,就drop table了
所以即使第2次自動收集統計資訊執行,當然不會收集不存在的物件了
tmp字首的表是否頻繁建立刪除,可透過如下指令碼定位與診斷,主要看created,last_ddl_time列的時間,是不是很新的時間,
大家知道自動統計資訊每天都會執行,所以可以在下述指令碼在2天重複執行,對比下,就知道tmp字首的表是否頻繁drop然後重建了
select owner,object_name,object_id,object_type,created,last_ddl_time,timestamp,status
from dba_objects
where object_name='tmp字首的表' ;
當然,這一切仍舊去客戶現場進行證實
沒有收集表的統計資訊,SQL在生成執行計劃時,該如何處理呢,我們知道,如果表上沒有統計資訊時,oracle會採用動態取樣技術去獲取表
及列和索引的統計資訊,大家注意標紅部分,表明採用了動態取樣技術
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost (%CPU)
|
Time
|
0
|
SELECT STATEMENT
|
|
|
|
23 (100)
|
|
1
|
TABLE ACCESS FULL
|
BD_BANK_TYPE
|
1
|
17
|
3 (0)
|
00:00:01
|
2
|
SORT AGGREGATE
|
|
1
|
87
|
|
|
3
|
FILTER
|
|
|
|
|
|
4
|
TABLE ACCESS BY INDEX ROWID
|
TMP_ACCNT_BALANCE
|
115
|
10005
|
5 (0)
|
00:00:01
|
5
|
INDEX RANGE SCAN
|
IDX_TMP_BALANCE_DATE
|
53
|
|
1 (0)
|
00:00:01
|
6
|
VIEW
|
index$_join$_004
|
1
|
104
|
3 (34)
|
00:00:01
|
7
|
HASH JOIN
|
|
|
|
|
|
8
|
INDEX RANGE SCAN
|
IDX_PROC_ACC_NUM_L1
|
1
|
104
|
1 (0)
|
00:00:01
|
9
|
INDEX RANGE SCAN
|
IDX_PROC_ACC_NUM_L2
|
1
|
104
|
1 (0)
|
00:00:01
|
10
|
SORT AGGREGATE
|
|
1
|
74
|
|
|
11
|
FILTER
|
|
|
|
|
|
12
|
TABLE ACCESS BY INDEX ROWID
|
TMP_ACCNT_BALANCE
|
132
|
9768
|
5 (0)
|
00:00:01
|
13
|
INDEX RANGE SCAN
|
IDX_TMP_BALANCE_DATE
|
53
|
|
1 (0)
|
00:00:01
|
14
|
VIEW
|
index$_join$_006
|
1
|
104
|
3 (34)
|
00:00:01
|
15
|
HASH JOIN
|
|
|
|
|
|
16
|
INDEX RANGE SCAN
|
IDX_PROC_ACC_NUM_L1
|
1
|
104
|
1 (0)
|
00:00:01
|
17
|
INDEX RANGE SCAN
|
IDX_PROC_ACC_NUM_L3
|
1
|
104
|
1 (0)
|
00:00:01
|
18
|
SORT AGGREGATE
|
|
1
|
63
|
|
|
19
|
FILTER
|
|
|
|
|
|
20
|
HASH JOIN
|
|
997
|
62811
|
5441 (1)
|
00:01:06
|
21
|
TABLE ACCESS BY INDEX ROWID
|
RA_AD_OFFICE_PAY
|
998
|
50898
|
5256 (1)
|
00:01:04
|
22
|
INDEX RANGE SCAN
|
INDEX_BUSINESS_DATE
|
28890
|
|
104 (0)
|
00:00:02
|
23
|
INDEX FAST FULL SCAN
|
PK_RBBOI
|
177K
|
2082K
|
184 (1)
|
00:00:03
|
24
|
VIEW
|
index$_join$_009
|
1
|
104
|
3 (34)
|
00:00:01
|
25
|
HASH JOIN
|
|
|
|
|
|
26
|
INDEX RANGE SCAN
|
IDX_PROC_ACC_NUM_L1
|
1
|
104
|
1 (0)
|
00:00:01
|
27
|
INDEX RANGE SCAN
|
IDX_PROC_ACC_NUM_L4
|
1
|
104
|
1 (0)
|
00:00:01
|
28
|
VIEW
|
|
1
|
335
|
23 (18)
|
00:00:01
|
29
|
SORT ORDER BY
|
|
1
|
234
|
23 (18)
|
00:00:01
|
30
|
FILTER
|
|
|
|
|
|
31
|
NESTED LOOPS
|
|
3
|
702
|
22 (14)
|
00:00:01
|
32
|
VIEW
|
VW_NSO_2
|
23
|
299
|
19 (11)
|
00:00:01
|
33
|
HASH UNIQUE
|
|
1
|
897
|
|
|
34
|
NESTED LOOPS
|
|
23
|
897
|
19 (11)
|
00:00:01
|
35
|
VIEW
|
VW_NSO_1
|
2
|
26
|
11 (19)
|
00:00:01
|
36
|
SORT UNIQUE
|
|
2
|
44
|
11 (82)
|
00:00:01
|
37
|
UNION-ALL
|
|
|
|
|
|
38
|
FAST DUAL
|
|
1
|
|
2 (0)
|
00:00:01
|
39
|
TABLE ACCESS BY INDEX ROWID
|
RM_PARTY_RELATION
|
1
|
44
|
7 (0)
|
00:00:01
|
40
|
INDEX RANGE SCAN
|
IDX_PARTYREL_PARENTID_VIEW
|
7
|
|
3 (0)
|
00:00:01
|
41
|
TABLE ACCESS BY INDEX ROWID
|
TMP_FTS_ACC_REL
|
11
|
286
|
4 (0)
|
00:00:01
|
42
|
INDEX RANGE SCAN
|
IDX_PROC_MAIN_CORP_ID
|
11
|
|
1 (0)
|
00:00:01
|
43
|
TABLE ACCESS BY INDEX ROWID
|
TMP_ACCNT_BALANCE
|
3
|
663
|
2 (0)
|
00:00:01
|
44
|
INDEX RANGE SCAN
|
IDX_TMP_PK_ACTUAL_ACCNT
|
3
|
|
1 (0)
|
00:00:01
|
45
|
FILTER
|
|
|
|
|
|
46
|
HASH GROUP BY
|
|
1
|
44
|
2078 (1)
|
00:00:25
|
47
|
TABLE ACCESS FULL
|
RM_PARTY_RELATION
|
1761
|
77484
|
2077 (1)
|
00:00:25
|
.dynamic sampling used for this statement
摘錄動態取樣官方註解
何時使用動態取樣
1, 對於查詢速度很快的SQL,比如僅執行不到幾秒,使用動態取樣大可不必,反而增大成本,影響效能,
2, 但是,在如下情形下,採用動態取樣是有益的:
? 使用動態取樣可以選取更好的執行計劃
? 動態取樣的時間僅佔更個SQL查詢的很小一部分
? SQL查詢會執行很多次
3, 動態取樣既適用於單表謂詞一部分,也適用於未採用動態取樣的常規統計資訊評估
如何使用動態取樣提升資料庫效能
透過引數optimizer_dynamic_samplingr控制動態取樣的級別,值為0-10,預設為2
? 0表示禁用動態取樣
? 值越大,動態取樣越明顯或者越強大,這個是基於取樣表是否收集過統計資訊以及取樣消耗的IO資源
@ 如果取樣表沒有資料插入,刪除或修改,動態取樣依舊可以重複執行
@ 如果配置optimizer_features_enable=小於9.2.0,則禁用動態取樣功能
動態取樣的取樣級別
l 動態取樣級別可以透過引數optimizer_dynamic_sampling或SQL HINT進行配置
l optimizer_dynamic_sampling配置值如下:
? level 0:禁用動態取樣
? level 1:如果滿足如下條件,則取樣所有沒有被收集統計資訊的表
SQL到少有1個表未採分析
未分析的表與另一個表進行關聯或者出現在子查詢
或不能 合併的檢視
沒有索引的未被分析的表
未被分析的表要比動態取樣分析的表更多的資料塊。預設 情況下,取樣的資料塊個數為32個資料塊
level 2:對所有未分析的表進行動態取樣,取樣資料塊個數是預設取樣資料塊個數的2倍
level 3:在level 2的基礎上,加上用於評估潛在的動態取樣謂詞的所有表。動態取樣資料塊個數,預設採取動態取樣預設的資料塊個數,對於未被分析過的表,取樣資料塊個數是預設的2倍
level 4:在level 3的基礎上,加上單表謂詞有2個的所有表。其它同上
level 5,6,7,8,9:適應用於之前所有的level,分別以上述取樣級別的2,4,8,32,128倍數進行動態取樣資料塊
level 10:滿足level 9,且掃描使用表上所有的資料塊,應用動態取樣
動態取樣在sql hint中應用,即dynamic_sampling:
level 0:同上
level 1:預設取樣32個數塊
level 2,3,4,5,6,7,8,9,同上,是預設動態取樣資料塊的2,4,8,16,32,64,128,256倍
level 10:動態取樣會讀取表所有的資料塊
測試結論:
1,如果表DML進行DML或大批次資料載入,且處於自動收集統計資訊job之外,是不會收集表相關統計資訊
2,如果儲存過程呼叫表,且表在儲存過程中狀態週期為建立,使用,刪除,依舊不會收集表相關統計資訊
(注:此儲存過程執行時間要短,不能與自動收集統計資訊重合)
3,透過dba_objects獲取表是否頻繁建立,存活週期很短
4,如果表沒有收集統計資訊,資料庫會採用動態取樣技術請及時收集表相關的統計資訊
5,如果表沒有收集統計資訊,也可以透過如下指令碼對比診斷,表統計資訊收集的歷史過程,此字典一般儲存31天的資料,如果依舊沒有資訊,
原因可能是上述的幾個原因之一
select operation,target,start_time,end_time
from dba_optstat_operations
where lower(target) like '%tmp字首的表%';
6, 也可能是與相關的SQL剛首次執行,正好未在自動收集統計資訊JOB之內執行,可以透過dba_hist_sql_stats進行診斷與確認