REM REM $Header: catio.sql,v 1.2 1993/02/23 15:25:12 HRIZVI Exp $ REM REM Copyright (c) 1991, 1996 by Oracle Corporation REM NAME REM catio.sql - I/O per table statistics REM DESCRIPTION REM Collect I/O per table (actually object) statistics by statistical REM sampling REM NOTES REM This works by sampling the buffer at the end of the buffer cache LRU REM list. The theory is that this buffer was read in at some point and REM therefore counts as a an IO. All buffers that are read in will REM eventually find themselves at the end of the LRU list. There is a REM stored procedure that periodically samples the buffer at the end of REM the lru list and a view that generates a database object name given REM the block number of the buffer. REM REM Note that this file will tell you the distribution of IOs REM between tables, but it will not tell you the exact number of IOs. REM REM The DBMSLOCK file must be loaded before this is loaded in order to REM get the definition of sleep(). REM MODIFIED (MM/DD/YY) Rem nmacnaug 09/03/96 - nxt_lru renamed to nxt_repl Rem hrizvi 02/09/93 - apply changes to x$bh REM jloaiza 11/03/92 - Creation /* Map an extent to a base object (table, index, ...) */ drop view extent_to_object; create view extent_to_object as select uet$.file# file# , uet$.block# lowb , uet$.block# + uet$.length - 1 highb , obj$.name name , 'TABLE' kind from tab$, uet$, obj$ where tab$.clu# is null and tab$.file# = uet$.segfile# and tab$.block# = uet$.segblock# and tab$.obj# = obj$.obj# union all select distinct uet$.file# file# , uet$.block# lowb , uet$.block# + uet$.length - 1 highb , obj$.name name , 'CLUSTER' kind from tab$, uet$, obj$ where tab$.clu# is not null and tab$.file# = uet$.segfile# and tab$.block# = uet$.segblock# and tab$.clu# = obj$.obj# union all select uet$.file# file# , uet$.block# lowb , uet$.block# + uet$.length - 1 highb , obj$.name name , 'INDEX' kind from ind$, uet$, obj$ where ind$.file# = uet$.segfile# and ind$.block# = uet$.segblock# and ind$.obj# = obj$.obj# union all select uet$.file# file# , uet$.block# lowb , uet$.block# + uet$.length - 1 highb , undo$.name name , 'ROLLBACK SEGMENT' kind from undo$, uet$ where undo$.file# = uet$.segfile# and undo$.block# = uet$.segblock# union all select uet$.file# file# , uet$.block# lowb , uet$.block# + uet$.length - 1 highb , 'TEMP SEGMENT' name , 'TEMP SEGMENT' kind from uet$, seg$ where seg$.file# = uet$.segfile# and seg$.block# = uet$.block# and seg$.type = 3 union all select file# , block# , length + block# , 'FREE EXTENT' , 'FREE EXTENT' from fet$; REM This table maps extents to database objects. This table must be REM dropped and recreated to include any new extents that are added REM after the last time it was created. Its purpose is to speedup REM the views created below. drop table extent_to_object_tab; create table extent_to_object_tab as select * from extent_to_object; create unique index extent_to_object_ind on extent_to_object_tab (file#, lowb); REM The IO_HISTOGRAM table contains samples of the block number of the block REM that is at the end of the buffer cache LRU list. drop table io_histogram; create table io_histogram (fileid number,blockid number, io_type varchar2(20)); REM This procedure periodically samples the buffer at the end of the lru list REM and then writes its blockid into the IO_HISTOGRAM table. drop procedure sample_io; create procedure sample_io (duration number, -- total sampling time in minutes sleep_time number -- time to sleep between taking samples in seconds ) is time_so_far number; tail_of_lru number; this_tail_of_lru number; last_file_id number; this_file_id number; last_block_id number; this_block_id number; block_flag number; begin time_so_far := 0; last_file_id := 0; last_block_id := 0; -- Get the tail of lru value, this can be in flux, so try it several times -- to be sure. tail_of_lru := 4000000000; -- init to very large value for i in 1..5 loop select min(nxt_repl) into this_tail_of_lru from x$bh; if (this_tail_of_lru < tail_of_lru) then tail_of_lru := this_tail_of_lru; end if; end loop; -- loop until time runs out while (time_so_far < duration * 60) loop -- get buffer at the end of the lru list begin select dbafil, dbablk, flag into this_file_id, this_block_id, block_flag from x$bh where ((nxt_repl = tail_of_lru) and (state = 1 or state = 2) and (rownum = 1)); exception when no_data_found then null; end; -- don't insert same buffer twice, this means no activity on lru list if (this_file_id != last_file_id AND this_block_id != last_block_id) then insert into io_histogram values (this_file_id, this_block_id, decode(bitand(block_flag,524288),0,'random','sequential')); end if; last_file_id := this_file_id; last_block_id := this_block_id; dbms_lock.sleep(sleep_time); -- go to sleep for a while time_so_far := time_so_far + sleep_time; end loop; end; / REM Create a view that summarizes the IO information per database object. drop view io_per_object; create view io_per_object as select name, kind, io_type, count(*) blocks_read from extent_to_object_tab e, io_histogram io where e.file# = io.fileid and blockid between e.lowb and e.highb group by name, kind, io_type;