runstats是《Oracle Database 9i/10g/11g編程藝術:深入數據庫體系結構》作者編寫的一個工具,能對做同一件事情的兩個不同方法進行比較,得出孰優孰劣的結果。我們只需要提供兩個不同的方法,余下的事情都由runstats負責。runstats只負責測量3個要素:
- 牆上時鍾或耗時時間:知道牆上時鍾或耗時時間很有用,不過這不是最重要的信息。
- 系統統計結果:會並排地i顯示每個方法做某件事(如執行一個解析調用)的次數,並展示出兩者之差
- 閂定(latching):這是這個報告的關鍵輸出。
要使用runstats,需要能訪問幾個V$視圖,並創建一個表來存儲統計結果,還要創建runstats包。為此,需要訪問4個V$表(就是那些神奇的動態性能表):V$STATNAME、V$MYSTAT和V$LATCH和V$TIMER。這四個表其實是別名,真正對象的名稱應為V_$STATNAME、V_$MYSTAT、 V_$LATCH、 V_$TIMER,並且都是在sys賬戶下。如果其他賬戶要訪問這四張表, 需要進行授權。我們需要再scott下進行操作,因此需要將這四張表的select權限授予給scott賬戶。下面進行具體操作。
1在sys賬戶下
1.1將V_$表的查詢權限授權給scott

--在sys賬戶下授權視圖查詢權限給scott grant SELECT on SYS.v_$statname to "SCOTT" ; grant SELECT on SYS.v_$mystat to "SCOTT" ; grant SELECT on SYS.v_$latch to "SCOTT" ; grant SELECT on SYS.v_$timer to "SCOTT" ;
2在scott賬戶下
2.1查詢V_$表

--在scott賬戶下測試視圖查詢,發現不能使用別名查詢,只能使用視圖真名 select * from SYS.v_$statname--成功 select * from SYS.v$statname--失敗
2.2創建視圖

--在scott賬戶下創建視圖 create or replace view stats as select 'STAT...' || a.name name, b.value from SYS.v_$statname a, SYS.v_$mystat b where a.statistic# = b.statistic# union all select 'LATCH.' || name, gets from SYS.v_$latch union all select 'STAT...Elapsed Time', hsecs from SYS.v_$timer;
2.3創建信息收集表

--創建信息收集表 create global temporary table run_stats ( runid varchar2(15), name varchar2(80), value int ) on commit preserve rows;
2.4創建runstats包

--創建包 create or replace package runstats_pkg as procedure rs_start; procedure rs_middle; procedure rs_stop( p_difference_threshold in number default 0 ); end; /
2.5創建包體

--創建包體 create or replace package body runstats_pkg as g_start number; g_run1 number; g_run2 number; procedure rs_start is begin delete from run_stats; insert into run_stats select 'before', stats.* from stats; g_start := dbms_utility.get_cpu_time; end; procedure rs_middle is begin g_run1 := (dbms_utility.get_cpu_time-g_start); insert into run_stats select 'after 1', stats.* from stats; g_start := dbms_utility.get_cpu_time; end; procedure rs_stop(p_difference_threshold in number default 0) is begin g_run2 := (dbms_utility.get_cpu_time-g_start); dbms_output.put_line ( 'Run1 ran in ' || g_run1 || ' cpu hsecs' ); dbms_output.put_line ( 'Run2 ran in ' || g_run2 || ' cpu hsecs' ); if ( g_run2 <> 0 ) then dbms_output.put_line ( 'run 1 ran in ' || round(g_run1/g_run2*100,2) || '% of the time' ); end if; dbms_output.put_line( chr(9) ); insert into run_stats select 'after 2', stats.* from stats; dbms_output.put_line ( rpad( 'Name', 30 ) || lpad( 'Run1', 12 ) || lpad( 'Run2', 12 ) || lpad( 'Diff', 12 ) ); for x in ( select rpad( a.name, 30 ) || to_char( b.value-a.value, '999,999,999' ) || to_char( c.value-b.value, '999,999,999' ) || to_char( ( (c.value-b.value)-(b.value-a.value)), '999,999,999' ) data from run_stats a, run_stats b, run_stats c where a.name = b.name and b.name = c.name and a.runid = 'before' and b.runid = 'after 1' and c.runid = 'after 2' and abs( (c.value-b.value) - (b.value-a.value) ) > p_difference_threshold order by abs( (c.value-b.value)-(b.value-a.value)) ) loop dbms_output.put_line( x.data ); end loop; dbms_output.put_line( chr(9) ); dbms_output.put_line ( 'Run1 latches total versus runs -- difference and pct' ); dbms_output.put_line ( lpad( 'Run1', 12 ) || lpad( 'Run2', 12 ) || lpad( 'Diff', 12 ) || lpad( 'Pct', 10 ) ); for x in ( select to_char( run1, '999,999,999' ) || to_char( run2, '999,999,999' ) || to_char( diff, '999,999,999' ) || to_char( round( run1/decode( run2, 0, to_number(0), run2) *100,2 ), '99,999.99' ) || '%' data from ( select sum(b.value-a.value) run1, sum(c.value-b.value) run2, sum( (c.value-b.value)-(b.value-a.value)) diff from run_stats a, run_stats b, run_stats c where a.name = b.name and b.name = c.name and a.runid = 'before' and b.runid = 'after 1' and c.runid = 'after 2' and a.name like 'LATCH%' ) ) loop dbms_output.put_line( x.data ); end loop; end; end; /
3.使用runstats
3.1創建表T

--創建表 create table t(x int);
3.2創建存儲過程proc1,使用了一條帶綁定變量的SQL語句

--創建存儲過程proc1 create or replace procedure proc1 as begin for i in 1 .. 10000 loop execute immediate 'insert into t values(:x)' using i; end loop; end; /
3.3創建存儲過程proc2,分別為要插入的每一行構造一條獨立的SQL語句

--創建存儲過程proc2 create or replace procedure proc2 as begin for i in 1 .. 10000 loop execute immediate 'insert into t values('||i||')'; end loop; end; /
3.4使dbms_output.put_line 生效
要使用dbms_output.put_line ,則必須在sqlplus中顯式聲明:
set serverout on
比如:
SQL> set serverout on SQL> exec dbms_output.put_line('asda'); asda--輸出結果 PL/SQL procedure successfully completed
3.5執行runstats中的方法以及兩個存儲過程

exec runstats_pkg.rs_start; exec proc1; exec runstats_pkg.rs_middle; exec proc2; exec runstats_pkg.rs_stop(10000); /
輸出結果為:

Run1 ran in 26 cpu hsecs Run2 ran in 267 cpu hsecs run 1 ran in 9.74% of the time Name Run1 Run2 Diff STAT...parse count (total) 15 10,016 10,001 STAT...session cursor cache hi 10,003 1 -10,002 STAT...consistent gets from ca 39 10,054 10,015 STAT...consistent gets from ca 70 10,087 10,017 STAT...consistent gets 70 10,087 10,017 STAT...db block gets 10,424 30,369 19,945 STAT...db block gets from cach 10,424 30,369 19,945 STAT...db block gets from cach 65 20,039 19,974 LATCH.cache buffers chains 51,209 71,216 20,007 LATCH.enqueue hash chains 60 20,122 20,062 LATCH.enqueues 44 20,109 20,065 STAT...session logical reads 10,494 40,456 29,962 STAT...recursive calls 10,131 40,144 30,013 LATCH.kks stats 3 33,343 33,340 STAT...session uga memory max 123,452 72,940 -50,512 LATCH.shared pool simulator 80 83,641 83,561 STAT...session pga memory 65,536 196,608 131,072 STAT...session uga memory 0 196,392 196,392 LATCH.row cache objects 228 210,126 209,898 LATCH.shared pool 20,151 339,848 319,697 Run1 latches total versus runs -- difference and pct Run1 Run2 Diff Pct 73,042 780,963 707,921 9.35% PL/SQL 過程已成功完成。