You may create the object with SYSTEM and execute as SYS
In any case be sure to grant these privileges to the owner
grant ANALYZE ANY to "USR"; grant CREATE ANY PROCEDURE to "USR"; grant CREATE PROCEDURE to "USR"; grant CREATE PUBLIC SYNONYM to "USR"; grant CREATE SESSION to "USR"; grant CREATE TABLE to "USR"; grant SELECT ANY DICTIONARY to "USR"; grant SELECT ANY TABLE to "USR"; |
Table XP_LAST_OPERATIONS
CREATE TABLE XP_LAST_OPERATIONS ( NAME VARCHAR2(50 BYTE), DESCRIPTION VARCHAR2(500 BYTE), DATETIME DATE, SEGMENT VARCHAR2(200 BYTE), XP_SESSION_NAME VARCHAR2(32 BYTE), OWNER VARCHAR2(20 BYTE) ); ALTER TABLE XP_LAST_OPERATIONS ADD (
UNIQUE (NAME)
USING INDEX);CREATE PUBLIC SYNONYM XP_LAST_OPERATIONS FOR XP_LAST_OPERATIONS; |
Table XP_STATS
CREATE TABLE XP_STATS ( OWNER VARCHAR2(15 BYTE) NOT NULL, SEGMENT_NAME VARCHAR2(30 BYTE) NOT NULL, PARTITION_NAME VARCHAR2(30 BYTE), BLOCK_CHANGES_WHEN_ANALYZED NUMBER, LAST_DB_BLOCK_CHANGES NUMBER DEFAULT 0, CURR_DB_BLOCK_CHANGES NUMBER, STATS_DATE DATE, LAST_CHECK_DATE DATE, SEGMENT_TYPE VARCHAR2(50 BYTE) NOT NULL, ANALYZED_IN_LAST_SESSION INTEGER DEFAULT 0 NOT NULL, JUST_INSERTED INTEGER, CURR_BLOCKS NUMBER, XP_SESSION_NAME VARCHAR2(32 BYTE), H_LAST_DATE DATE, H_LAST_SESSION VARCHAR2(32 BYTE), H_ANALYZED_IN_LAST_SESSION INTEGER DEFAULT 0 NOT NULL ); CREATE INDEX CUSTOM_STATS_TUNING ON XP_STATS (OWNER, SEGMENT_NAME); CREATE UNIQUE INDEX CUSTOM_STATS_UNIQUE ON XP_STATS (OWNER, PARTITION_NAME, SEGMENT_NAME); ALTER TABLE XP_STATS ADD ( CONSTRAINT JUST_INSERTED_NOT_NULL CHECK (not just_inserted is null)); CREATE PUBLIC SYNONYM XP_STATS FOR XP_STATS; |
Table XP_STAT_LOG
CREATE TABLE XP_STAT_LOG ( MSG VARCHAR2(2000 BYTE), DATA DATE DEFAULT sysdate, LOG_LEVEL NUMBER, PROG TIMESTAMP(6), SEGMENT VARCHAR2(200 BYTE), XP_SESSION_NAME VARCHAR2(32 BYTE), OWNER VARCHAR2(20 BYTE) ); CREATE PUBLIC SYNONYM XP_STAT_LOG FOR XP_STAT_LOG; |
Table XP_COLUMN_HISTOGRAMS
CREATE TABLE XP_COLUMN_HISTOGRAMS ( OWNER VARCHAR2(15 BYTE) NOT NULL, SEGMENT_NAME VARCHAR2(30 BYTE) NOT NULL, PARTITION_NAME VARCHAR2(30 BYTE), METHOD_OPT VARCHAR2(400 BYTE) NOT NULL ); CREATE INDEX XP_HIST_TUNING ON XP_COLUMN_HISTOGRAMS (OWNER, SEGMENT_NAME); CREATE UNIQUE INDEX XP_HIST_UNIQUE ON XP_COLUMN_HISTOGRAMS (OWNER, SEGMENT_NAME, PARTITION_NAME); CREATE PUBLIC SYNONYM XP_COLUMN_HISTOGRAMS FOR XP_COLUMN_HISTOGRAMS; |
View XPV_STATS
CREATE OR REPLACE VIEW XPV_STATS AS
select x.*
--, (10*curr_blocks/100) "10_PERC_OF_BLOCKS"
--, (10*curr_blocks/100)+ curr_db_block_changes REQ_BLOCKS_CHNG_FOR_10
--, sign(curr_db_block_changes - ((10*curr_blocks/100)+ curr_db_block_changes)) STATS_FOR_10
, owner||'.'||segment_name||'.'||partition_name own_seg_part
, xp_stat.getLogForSegment(owner||'.'||segment_name||'.'||partition_name, xp_session_name) segment_log
from xp_stats x; |
View XPV_STATS_NOW
CREATE OR REPLACE VIEW XPV_STATS_NOW AS
select a.*
, (10*blocks/100) "10_PERC_OF_BLOCKS"
, (10*blocks/100)+ curr_block_changes REQ_BLOCKS_CHNG_FOR_10
, sign(curr_block_changes - ((10*blocks/100)+ curr_block_changes)) STATS_FOR_10
from (
select s.*,
nvl((select value from v$segment_statistics where statistic#=2 and owner=s.owner and object_name=s.segment_name
and nvl(subobject_name, ' ')=nvl(s.partition_name, ' ')), 0) curr_block_changes
from dba_segments s
) a;CREATE PUBLIC SYNONYM XPV_STATS_NOW FOR SYSTEM.XPV_STATS_NOW; |
View XPV_ANALYZABLE_HISTOGRAMS
CREATE OR REPLACE VIEW XPV_ANALYZABLE_HISTOGRAMS AS
select nvl(x.owner, h.owner) owner, nvl(x.segment_name, h.segment_name) segment_name,
nvl(x.partition_name, h.partition_name) partition_name,
nvl(x.owner, h.owner)||'.'||nvl(x.segment_name, h.segment_name)||'.'||nvl(x.partition_name, h.partition_name) name,
h.method_opt, segment_exists, partition_exists, x.analyzed_in_last_session,
mispelled_partition
from XPV_COLUMN_HISTOGRAMS h, xp_stats x
where x.owner (+)= h.owner and x.segment_name (+)= h.segment_name
and nvl(x.partition_name, ' ') = nvl(h.partition_name, nvl(x.partition_name, ' ')); |
View XPV_COLUMN_HISTOGRAMS
CREATE OR REPLACE FORCE VIEW XPV_COLUMN_HISTOGRAMS AS select a.* , decode(partition_name, null, 0, decode(partition_exists, 0, 1, 0)) mispelled_partition from ( select h.owner||'.'||h.segment_name||'.'||h.partition_name name, method_opt , nvl((select 1 from xp_stats x where owner = h.owner and segment_name = h.segment_name and rownum = 1),0) segment_exists , nvl((select 1 from xp_stats x where owner = h.owner and segment_name = h.segment_name and partition_name = h.partition_name),0) partition_exists , h.owner, h.segment_name, h.partition_name from xp_column_histograms h ) a; CREATE PUBLIC SYNONYM XPV_COLUMN_HISTOGRAMS FOR SYSTEM.XPV_COLUMN_HISTOGRAMS; |
View XPV_REAL_TIME_LAST_ANALYZED
CREATE OR REPLACE VIEW XPV_REAL_TIME_LAST_ANALYZED AS select a.owner, a.segment_name, a.partition_name, a.segment_type, a.owner||'.'||a.segment_name||'.'||a.partition_name name, nvl(nvl(nvl(last_analyzed_index, last_analyzed_table), last_analyzed_ind_part), last_analyzed_tab_part) last_analyzed from ( select s.owner, s.segment_name, s.partition_name, s.segment_type , (select last_analyzed from dba_indexes where s.segment_type='INDEX' and owner = s.owner and index_name = s.segment_name) last_analyzed_index , (select last_analyzed from dba_ind_partitions where s.segment_type='INDEX PARTITION' and index_owner = s.owner and index_name = s.segment_name and partition_name = s.partition_name) last_analyzed_ind_part , (select last_analyzed from dba_tables where s.segment_type='TABLE' and owner = s.owner and table_name = s.segment_name) last_analyzed_table , (select last_analyzed from dba_tab_partitions where s.segment_type='TABLE PARTITION' and table_owner = s.owner and table_name = s.segment_name and partition_name = s.partition_name) last_analyzed_tab_part from dba_segments s ) a; CREATE PUBLIC SYNONYM XPV_REAL_TIME_LAST_ANALYZED FOR SYSTEM.XPV_REAL_TIME_LAST_ANALYZED; |
View XPV_JOIN_REDO
CREATE OR REPLACE FORCE VIEW XPV_JOIN_REDO AS select xp.*, dml_count, blocks, num_rows , abs(curr_db_block_changes -block_changes_when_analyzed) blocks_diff from ( select owner, segment_name, sum(block_changes_when_analyzed) block_changes_when_analyzed , sum(last_db_block_changes) last_db_block_changes , sum(curr_db_block_changes) curr_db_block_changes , max(stats_date) max_stats_date, max(last_check_date) max_last_check_date , sum(curr_blocks) curr_blocks from xp_stats where owner = 'VPO' and segment_type ='TABLE' or segment_type ='TABLE PARTITION' group by owner, segment_name ) xp, ( select st.seg_owner, st.seg_name, count(*) dml_count, sum(t.blocks) blocks , sum(t.num_rows) num_rows from storico.log_storico_data st, dba_tables t where st.seg_owner=t.owner and st.SEG_NAME=t.table_name and st.seg_owner='VPO' group by st.seg_owner, st.seg_name ) enrico where enrico.seg_owner = xp.owner and enrico.seg_name = xp.segment_name and block_changes_when_analyzed <> curr_db_block_changes; |
package
xp_statCREATE OR REPLACE package xp_stat authid current_user is DEBUG number := 0; INFO number := 1; WARNING number := 2; ERROR number := 3; ALWAYS number := 4; minimalLogLevel number := INFO; module_name varchar2(50) := 'XP_STAT'; action_name_during_stats varchar2(50) := 'Taking stats for schema '; --begin --xp_stat.PRINTSAMPLEPERCFORBLOCKCHANGES(100, 2, 1.2); --end; --A 2 blocks segment will only be analyzed when all its blocks will be changed, while for a --largest segment a smaller percentual of changed blocks will be needed to take stats procedure printSamplePercForBlockChanges(percBase number, blocksMultipl number, logBase number); procedure takeStats(m_owner varchar2, percentual_sample number default 49, m_degree number default null, percForTables number default 100, percForIndexes number default 100, logBaseTables number default 1.2, logBaseIndexes number default 1.175, m_minimalLogLevel number default INFO, m_truncateLogTable boolean default false, m_simulation_only boolean default false, m_stop_on_exception boolean default false, m_log_retention_days number default 3, m_launch_notes varchar2 default null); function getLogForSegment(m_segment varchar2, m_session varchar2 default null, out_to_console boolean default false, logDate boolean default false) return varchar2; end xp_stat; |
package
body xp_statCREATE OR REPLACE package body xp_stat is
cr varchar2(4) := chr(13)||chr(10);
function boolToString(b boolean) return varchar2 is
begin
if b then
return 'True';
else return 'False';
end if;
end;
procedure outLongString(newString varchar2) is
i integer;
begin
i := 1;
loop
dbms_output.put_line(substr(newString, i, 255));
i := i + 255;
exit when i > length(newString);
end loop;
end;
procedure msg(text varchar2, logLevel number, m_owner varchar2, m_segment varchar2, m_xp_session_name varchar2) is
pragma autonomous_transaction;
t date;
n_owner varchar2(50);
begin
t := sysdate;
n_owner := m_owner;
if (m_owner is null) then
n_owner := '';
end if;
if logLevel >= minimalLogLevel then
insert into xp_stat_log(msg, data, log_level, prog, segment, xp_session_name, owner) values
(text, t, logLevel, LOCALTIMESTAMP, m_segment, m_xp_session_name, n_owner);
end if;
update xp_last_operations set description = text, datetime = t,
segment = m_segment, xp_session_name = m_xp_session_name
where name = 'XP_STAT_LAST_LOG'
and owner = n_owner;
if sql%rowcount = 0 then
insert into xp_last_operations (name, owner, description, datetime, segment, xp_session_name)
values('XP_STAT_LAST_LOG', n_owner, text, t, m_segment, m_xp_session_name);
end if;
commit;
end;
procedure clearLogTable(until_date date, m_xp_session_name varchar2, m_owner varchar2) is
pragma autonomous_transaction;
m_until_date date;
begin
if until_date is null then
select max(data) into m_until_date from xp_stat_log;
else m_until_date := until_date;
end if;
delete from xp_last_operations where owner = m_owner;
delete from xp_stat_log where data <= m_until_date and owner = m_owner;
commit;
msg('Older logs deleted until '|| to_char(m_until_date, 'dd/mm/yyyy hh24.mi.ss'), warning, m_owner, null, m_xp_session_name);
commit;
end;
function numc(n number) return varchar2 is
begin
return to_char(n, 'FM999,999,999,990, 00');
end;
function c(n in number) return varchar2 is
mask varchar2(30);
result varchar2(50);
begin
--if hasDecimali(n) > 0 then
-- mask :='FM999,999,999,999.99';
--else mask := 'FM999,999,999,999';
--end if;
mask := 'FM999,999,999,990';
result := to_char(n, mask);
result := replace(result, ',', '*');
result := replace(result, '.', ',');
result := replace(result, '*', '.');
return result;
--return substr(result, length(result), 1);
end;
procedure takeStatsForTable(m_owner varchar2, m_tabName varchar2, m_partName varchar2,
percentual_sample number, m_degree number, m_xp_session_name varchar2
, m_method_opt VARCHAR2, m_granularity varchar2) is
num_rows NUMBER;
num_blocks NUMBER;
avg_row_len NUMBER;
error_message varchar2(4000);
BEGIN
msg('Taking stats for table at ' || percentual_sample || '%, degree ' || m_degree ||
', method_opt ' || m_method_opt || ', granularity ' || m_granularity
, warning,m_owner,
m_owner||'.'||m_tabName||'.'||m_partName, m_xp_session_name);
--Remember Oracle may change default values with newest releases,
--so this approach avoid any troubles
begin
--Per gli istogrammi
if (not m_method_opt is null)and(length(m_method_opt)>0) then
DBMS_STATS.GATHER_TABLE_STATS (
ownname=>m_owner,
tabname=>m_tabName,
partname=>m_partName,
estimate_percent=>percentual_sample,
--block_sample BOOLEAN DEFAULT FALSE,
method_opt=>m_method_opt,
degree=>m_degree,
granularity=>m_granularity,
--granularity VARCHAR2 DEFAULT 'DEFAULT',
cascade=>true
--stattab VARCHAR2 DEFAULT NULL,
--statid VARCHAR2 DEFAULT NULL,
--statown VARCHAR2 DEFAULT NULL,
--no_invalidate BOOLEAN DEFAULT FALSE
);
else
DBMS_STATS.GATHER_TABLE_STATS (
ownname=>m_owner,
tabname=>m_tabName,
partname=>m_partName,
estimate_percent=>percentual_sample,
--block_sample BOOLEAN DEFAULT FALSE,
--method_opt VARCHAR2 DEFAULT ?FOR ALL COLUMNS SIZE 1?,
degree=>m_degree,
granularity=>m_granularity,
cascade=>true
--stattab VARCHAR2 DEFAULT NULL,
--statid VARCHAR2 DEFAULT NULL,
--statown VARCHAR2 DEFAULT NULL,
--no_invalidate BOOLEAN DEFAULT FALSE
);
end if;
exception
when others then
error_message := 'Exception while taking stats for table segment.';
if (not m_method_opt is null)and(length(m_method_opt)>0) then
error_message := error_message || 'And histograms using: ' || m_method_opt;
end if;
error_message := error_message || sqlerrm(sqlcode);
msg(error_message, ERROR,m_owner, m_owner||'.'||m_tabName||'.'||m_partName, m_xp_session_name);
raise;
end;
end;
procedure takeStatsForIndex(m_owner varchar2, m_indexName varchar2, m_partName varchar2,
percentual_sample number, m_degree number, m_xp_session_name varchar2) is
begin
msg('Taking stats for index at ' || percentual_sample || '%, degree ' || m_degree
, warning,m_owner,
m_owner||'.'||m_indexName||'.'||m_partName, m_xp_session_name);
if(not m_partName is null)or(length(m_partName)>0) then
DBMS_STATS.GATHER_INDEX_STATS (
ownname=>m_owner,
indname=>m_indexName,
partname=>m_partName,
estimate_percent=>percentual_sample,
--stattab VARCHAR2 DEFAULT NULL,
--statid VARCHAR2 DEFAULT NULL,
--statown VARCHAR2 DEFAULT NULL,
degree=>m_degree
--granularity VARCHAR2 DEFAULT ?DEFAULT?,
--no_invalidate BOOLEAN DEFAULT FALSE
);
else
DBMS_STATS.GATHER_INDEX_STATS (
ownname=>m_owner,
indname=>m_indexName,
estimate_percent=>percentual_sample);
end if;
exception
when others then
msg('Exception while taking stats for index: '||sqlerrm(sqlcode), ERROR,m_owner,
m_owner||'.'||m_indexName||'.'||m_partName, m_xp_session_name);
raise;
end;
procedure takeStatsForObject(m_owner varchar2, m_object_name varchar2, m_subobject_name varchar2,
segment_type varchar2, percentual_sample number, m_degree number,
m_simulation_only boolean, m_xp_session_name varchar2,
m_granularity varchar2) is
begin
if not m_simulation_only then
if (segment_type = 'TABLE')or(segment_type = 'TABLE PARTITION') then
--msg('Going to table', 'INFO');
takeStatsForTable(m_owner, m_object_name, m_subobject_name, percentual_sample, m_degree,
m_xp_session_name, null, m_granularity);
elsif (segment_type = 'INDEX')or(segment_type = 'INDEX PARTITION') then
takeStatsForIndex(m_owner, m_object_name, m_subobject_name, percentual_sample,
m_degree, m_xp_session_name);
elsif (segment_type = 'LOBINDEX') then
msg('Segment is LOBINDEX no stats allowed', info, m_owner, m_owner||'.'||m_object_name||'.'||m_subobject_name,
m_xp_session_name);
elsif (segment_type = 'LOBSEGMENT') then
msg('Segment is LOBSEGMENT no stats allowed', info, m_owner, m_owner||'.'||m_object_name||'.'||m_subobject_name,
m_xp_session_name);
else msg('****Segment type for is '||segment_type||' what is it?****', ERROR, m_owner, m_owner||'.'||m_object_name||'.'||m_subobject_name,
m_xp_session_name);
end if;
else
msg('SIMULATION MODE, stats would be caught for segment '||segment_type, warning, m_owner, m_owner||'.'||m_object_name||'.'||m_subobject_name,
m_xp_session_name);
end if;
end;
procedure checkForDroppedSegments(m_xp_session_name varchar2, m_owner varchar2) is
begin
msg('Deleting dropped segments from cust table...', INFO, m_owner, null, m_xp_session_name);
delete from xp_stats where owner||'.'||segment_name||'.'||partition_name in (
select owner||'.'||segment_name||'.'||partition_name from xp_stats where owner = upper(m_owner)
minus
select owner||'.'||segment_name||'.'||partition_name from dba_segments where owner = upper(m_owner));
msg('...done', INFO, m_owner, null, m_xp_session_name);
exception
when others then
msg('Exception while checking for dropped segments: '||sqlerrm(sqlcode), ERROR, m_owner, null,
m_xp_session_name);
raise;
end;
function getAlreadyRunningStatus(m_schema varchar2) return varchar2 is
c varchar2(50);
begin
begin
select status||', SPID:'||p.spid into c from v$session s,v$process p
where module = module_name
and p.addr = s.paddr
and action = action_name_during_stats||upper(m_schema)
and rownum = 1;
exception
when no_data_found then
return null;
end;
return c;
end;
function calcPercForBlockChanges(percBase number, blocks number, logBase number
, m_segment varchar2 default null, m_xp_session_name varchar2 default null,
m_owner varchar2 default '') return number is
printLog boolean := false;
result number;
begin
printLog := (not m_segment is null)and (not m_xp_session_name is null);
if printLog then
msg('Calculating percentual of block changes for segment ' || nvl(m_segment, 'null') || ' having '||
blocks || ' blocks. Base percentual is ' || percBase ||
' and base logarithm is ' || logBase, INFO,m_owner, m_segment, m_xp_session_name);
end if;
result := percBase - log(logBase, blocks);
if printLog then
msg('Calculated percentual is '||percBase ||' - log('||logBase||', '||blocks||') = '||result,
INFO, m_owner, m_segment, m_xp_session_name);
end if;
return result;
end;
procedure printSamplePercForBlockChanges(percBase number, blocksMultipl number, logBase number) is
i number := 1;
begin
loop
dbms_output.put_line('%'|| to_char(calcPercForBlockChanges(percBase, i, logBase, ''), '99.99') ||' Blck: '|| c(i));
exit when i > 100000000;
i := i * blocksMultipl;
end loop;
end;
procedure calculateHistograms(m_owner varchar2, percentual_sample number
, m_degree number
, m_simulation_only boolean
, m_stop_on_exception boolean
, m_xp_session_name varchar2) is
cursor c_xpv_column_histograms(m_owner varchar2) is
select *
from xpv_analyzable_histograms where owner = upper(m_owner);
mc_xpv_column_histograms c_xpv_column_histograms%rowtype;
last_analyzed boolean;
granularity varchar2(50);
begin
--*************************
--* H I S T O G R A M M I *
--*************************
msg('Checking user data input for histograms '||m_owner||' schema...', INFO, m_owner, null,
m_xp_session_name);
open c_xpv_column_histograms(m_owner);
fetch c_xpv_column_histograms into mc_xpv_column_histograms;
loop
begin
exit when c_xpv_column_histograms%notfound;
if mc_xpv_column_histograms.mispelled_partition > 0 then
msg('The partition specified for histograms calculation does not exists', ERROR, m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
elsif mc_xpv_column_histograms.segment_exists <= 0 then
msg('The segment specified for histograms calculation does not exists', ERROR,m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
elsif mc_xpv_column_histograms.analyzed_in_last_session > 0 then
begin
msg('Calculating histograms using: '|| mc_xpv_column_histograms.method_opt, Warning, m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
if m_simulation_only then
msg('SIMULATION MODE, histograms stats should be taken now using '||
mc_xpv_column_histograms.method_opt, warning, m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
else
--Se ho una partizione allora la granularita e PARTITION,
--e le statistiche globali non sono aggiornate
--altrimenti va in granularita DEFAULT che di fatto ricalcola
--le statistiche per tutta la tabella da capo
if (not mc_xpv_column_histograms.partition_name is null) and
(length(mc_xpv_column_histograms.partition_name) > 0) then
granularity := 'PARTITION';
else
granularity := 'DEFAULT';
end if;
takeStatsForTable(m_owner=>mc_xpv_column_histograms.owner,
m_tabName=>mc_xpv_column_histograms.segment_name,
m_partName=>mc_xpv_column_histograms.partition_name,
percentual_sample=>percentual_sample,
m_degree=>m_degree,
m_xp_session_name=>m_xp_session_name,
m_method_opt=>mc_xpv_column_histograms.method_opt,
m_granularity=>granularity);
end if;
update xp_stats set h_last_date = sysdate, h_last_session = m_xp_session_name
, h_analyzed_in_last_session = 1 where owner = mc_xpv_column_histograms.owner
and segment_name = mc_xpv_column_histograms.segment_name and
nvl(partition_name, ' ') = nvl(mc_xpv_column_histograms.partition_name, ' ');
if SQL%rowcount >0 then
msg('xp_stats table updated', INFO, m_owner, mc_xpv_column_histograms.name, m_xp_session_name);
else
msg('No matching on were clause while updating segment on xp_stats table', ERROR,m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
end if;
fetch c_xpv_column_histograms into mc_xpv_column_histograms;
exception
when others then
msg('Exception while calculating histograms for segment.' ||sqlerrm(sqlcode), ERROR, m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
if m_stop_on_exception then
raise;
end if;
end;
end if;
fetch c_xpv_column_histograms into mc_xpv_column_histograms;
exception
when others then
msg('Exception while calculating histograms for segment.' ||sqlerrm(sqlcode), ERROR,m_owner,
mc_xpv_column_histograms.name, m_xp_session_name);
if m_stop_on_exception then
raise;
end if;
end;
end loop;
close c_xpv_column_histograms;
msg('...done', INFO, m_owner, null, m_xp_session_name);
-- msg('Taking histograms for '||m_owner||' schema...', INFO, null,
-- m_xp_session_name);
-- open mc_xpv_column_histograms(m_owner);
-- fetch c_h into mc_h;
-- loop
-- begin
-- exit when c_h%notfound;
-- msg('Calculating histograms using: '|| mc_xpv_column_histograms.method_opt, INFO,
-- mc_xpv_column_histograms.name, m_xp_session_name);
-- if m_simulation_only then
-- msg('SIMULATION MODE, histograms stats should be taken now using '|| mc_xpv_column_histograms.method_opt, INFO,
-- mc_h.name, m_xp_session_name);
-- else
-- takeStatsForTable(m_owner=>mc_h.owner,
-- m_tabName=>mc_h.segment_name,
-- m_partName=>mc_h.partition_name,
-- percentual_sample=>percentual_sample, m_degree=>m_degree,
-- m_xp_session_name=>m_xp_session_name,
-- m_method_opt=>mc_h.method_opt);
-- end if;
-- fetch c_h into mc_h;
-- exception
-- when others then
-- msg('Exception while calculating histograms for segment.' ||sqlerrm(sqlcode), ERROR,
-- mc_h.name, m_xp_session_name);
-- if m_stop_on_exception then
-- raise;
-- end if;
-- end;
-- end loop;
-- close c_h;
-- msg('Histograms taken', INFO, null, m_xp_session_name);
end;
procedure takeStats(m_owner varchar2, percentual_sample number default 49,
m_degree number default null,
percForTables number default 100,
percForIndexes number default 100,
logBaseTables number default 1.2,
logBaseIndexes number default 1.175,
m_minimalLogLevel number default INFO,
m_truncateLogTable boolean default false,
m_simulation_only boolean default false,
m_stop_on_exception boolean default false,
m_log_retention_days number default 3,
m_launch_notes varchar2 default null) is
i varchar2(200);
cursor c_new_segments(m_owner varchar2) is
select * from (
select owner, segment_name, partition_name, segment_type
from dba_segments
where owner = upper(m_owner)
minus
select owner, segment_name, partition_name, segment_type
from xp_stats
where owner = upper(m_owner)
)
--where not segment_type in ('INDEX', 'INDEX PARTITION')
order by owner, segment_name;
mc_new_segments c_new_segments%rowtype;
cursor c_xp_stats is
select xp_stats.*, xp_stats.rowid from xp_stats where owner = (upper(m_owner));
mc_xp_stats c_xp_stats%rowtype;
mc_xp_stats_rowid UROWID;
actualDbBlockChanges number;
custDbBlockChanges number;
m_existsInCust boolean;
--m_dba_segments dba_segments%rowtype;
diffBlocksChanged number;
requiredBlocksForStats number;
TYPE r_segment_statistics is record ( value number, just_inserted number);
TYPE t_segment_statistics IS TABLE OF r_segment_statistics INDEX BY VARCHAR2(150);
mt_segment_statistics t_segment_statistics;
cursor c_segment_statistics(m_owner varchar2) is
select owner||'.'||object_name||'.'||subobject_name as name, value
from v$segment_statistics where statistic#=2 and
owner = upper(m_owner);
mc_segment_statistics c_segment_statistics%rowtype;
TYPE r_dba_segments is record (owner varchar2(20), segment_name varchar2(50),
partition_name varchar2(50), segment_type varchar2(30),
name varchar2(120), bytes number, blocks number,
will_take_stats boolean, block_changes_when_analyzed number,
curr_db_block_changes number, stats_date date, last_check_date date,
analyzed_in_last_session integer, just_inserted integer,
last_db_block_changes number, rowidForXp_stats rowid);
mr_dba_segments r_dba_segments;
cursor c_dba_segments(m_owner varchar2) is
select owner, segment_name, partition_name, segment_type,
owner||'.'||segment_name||'.'||partition_name name, bytes, blocks
from dba_segments
where owner = upper(m_owner)
--and not segment_type in ('INDEX', 'INDEX PARTITION')
order by owner, segment_name;
mc_dba_segments c_dba_segments%rowtype;
TYPE t_dba_segments IS TABLE OF r_dba_segments INDEX BY VARCHAR2(150);
mt_dba_segments t_dba_segments;
TYPE r_part_tables_analyzed is record(owner varchar2(20), table_name varchar2(50));
mr_part_tables_analyzed r_part_tables_analyzed;
TYPE t_part_tables_analyzed IS TABLE OF r_part_tables_analyzed INDEX BY VARCHAR2(150);
mt_part_tables_analyzed t_part_tables_analyzed;
cursor c_XPV_REAL_TIME_LAST_ANALYZED(m_owner varchar2) is
select name, last_analyzed
from XPV_REAL_TIME_LAST_ANALYZED where owner = upper(m_owner);
mc_XPV_REAL_TIME_LAST_ANALYZED c_XPV_REAL_TIME_LAST_ANALYZED%rowtype;
instance_startup date;
will_take_stats number;
msg_program_already_running varchar2(500);
m_xp_session_name varchar2(32);
session_status varchar2(50);
actual_db_block_changes number;
m_just_inserted number;
tNow date;
percBlocksChanged number;
beginMsg varchar2(500);
realTimeLastAnalyzed date;
msgRealTimeLastAnalyzed varchar2(500);
cascade_stats boolean;
max_blocks_to_force_cascade integer := 64;
m_granularity varchar2(50);
--LONGOPS
totBlocksToAnalyze number := 0;
totObjectsToAnalyze number := 0;
rindexObjectsToAnalyze BINARY_INTEGER;
rindexBlocksToAnalyze BINARY_INTEGER;
slnoBlocksToAnalyze BINARY_INTEGER;
slnoObjectsToAnalyze BINARY_INTEGER;
sofarBlocksToAnalyze number;
sofarObjectsToAnalyze number;
objbLOCKSToAnalyze BINARY_INTEGER;
objObjectsToAnalyze BINARY_INTEGER;
begin
m_xp_session_name := sys_guid();
minimalLogLevel := m_minimalLogLevel;
session_status := getAlreadyRunningStatus(m_owner);
if (not session_status is null) and (length(session_status) >0) then
msg_program_already_running := 'A session with same module('||module_name||') and same action is already opened, exiting now.' ||
' Anyway this program may be run concurrently with different schema. The session is marked as '|| session_status;
msg(msg_program_already_running, WARNING, m_owner, null, m_xp_session_name);
raise_application_error(-20001, msg_program_already_running);
end if;
DBMS_APPLICATION_INFO.SET_MODULE(
module_name => module_name,
action_name => action_name_during_stats||upper(m_owner));
if (m_truncateLogTable) then
clearLogTable(null, m_xp_session_name, m_owner);
else clearLogTable(sysdate - m_log_retention_days, m_xp_session_name, m_owner);
end if;
select startup_time into instance_startup from v$instance;
beginMsg := 'Begin procedure.';
if (not m_launch_Notes is null) and (not length(m_launch_Notes)<=0) then
beginMsg := beginMsg || ' ' || m_launch_Notes;
end if;
msg(beginMsg, ALWAYS, m_owner, null, m_xp_session_name);
checkForDroppedSegments(m_xp_session_name, m_owner);
msg('Program session is ' ||m_xp_session_name, INFO, m_owner, null, m_xp_session_name);
msg('Creating a memory structure for all current block changes...', INFO, m_owner, null, m_xp_session_name);
open c_segment_statistics(m_owner);
fetch c_segment_statistics into mc_segment_statistics;
loop
exit when c_segment_statistics%notfound;
mt_segment_statistics(mc_segment_statistics.name).value := mc_segment_statistics.value;
msg('Storing current block changes (' ||mc_segment_statistics.value|| ') for segment',
DEBUG, m_owner, mc_segment_statistics.name, m_xp_session_name);
fetch c_segment_statistics into mc_segment_statistics;
end loop;
close c_segment_statistics;
msg('...done', INFO, m_owner, null, m_xp_session_name);
msg('Creating a memory structure for all segments of '||m_owner||' schema...', INFO, m_owner, null,
m_xp_session_name);
open c_dba_segments(m_owner);
fetch c_dba_segments into mc_dba_segments;
loop
exit when c_dba_segments%notfound;
mr_dba_segments.owner := mc_dba_segments.owner;
mr_dba_segments.segment_name := mc_dba_segments.segment_name;
mr_dba_segments.partition_name := mc_dba_segments.partition_name;
mr_dba_segments.segment_type := mc_dba_segments.segment_type;
mr_dba_segments.name := mc_dba_segments.name;
mr_dba_segments.bytes := mc_dba_segments.bytes;
mr_dba_segments.blocks := mc_dba_segments.blocks;
mr_dba_segments.will_take_stats := false;
mt_dba_segments(mc_dba_segments.name) := mr_dba_segments;
msg('Storing segment data for segment', DEBUG, m_owner, mc_dba_segments.name, m_xp_session_name);
fetch c_dba_segments into mc_dba_segments;
end loop;
close c_dba_segments;
msg('...done', INFO, m_owner, null, m_xp_session_name);
msg('Inserting new segments in cust table', INFO, m_owner, null, m_xp_session_name);
open c_new_segments(m_owner);
fetch c_new_segments into mc_new_segments;
loop
begin
exit when c_new_segments%notfound;
begin
actualDbBlockChanges := mt_segment_statistics(mc_new_segments.owner||'.'||mc_new_segments.segment_name||'.'
||mc_new_segments.partition_name).value;
exception
when no_data_found then
actualDbBlockChanges := 0;
end;
if actualDbBlockChanges is null then
actualDbBlockChanges := 0;
end if;
msg('Inserting new segment ', INFO, m_owner, mc_new_segments.owner||'.'||mc_new_segments.segment_name||'.'||
mc_new_segments.partition_name, m_xp_session_name);
insert into xp_stats (owner, segment_name, partition_name, curr_db_block_changes, block_changes_when_analyzed,
segment_type, just_inserted, curr_blocks, xp_session_name)
values (mc_new_segments.owner, mc_new_segments.segment_name, mc_new_segments.partition_name, actualDbBlockChanges, actualDbBlockChanges,
mc_new_segments.segment_type, 1,
mt_dba_segments(mc_new_segments.owner||'.'||mc_new_segments.segment_name||'.'
||mc_new_segments.partition_name).blocks,
m_xp_session_name);
msg('Segment inserted ', INFO, m_owner, mc_new_segments.owner||'.'||mc_new_segments.segment_name||'.'||
mc_new_segments.partition_name, m_xp_session_name);
mt_segment_statistics(mc_new_segments.owner||'.'||mc_new_segments.segment_name||'.'
||mc_new_segments.partition_name).just_inserted := 1;
exception
when others then
msg('Exception while inserting new segment : ' ||sqlerrm(sqlcode), ERROR,m_owner,
mc_new_segments.owner||'.'||mc_new_segments.segment_name||'.'
||mc_new_segments.partition_name, m_xp_session_name);
if m_stop_on_exception then raise;
end if;
end;
fetch c_new_segments into mc_new_segments;
end loop;
close c_new_segments;
msg('Done', INFO, m_owner, null, m_xp_session_name);
open c_xp_stats;
fetch c_xp_stats into mc_xp_stats;
loop
exit when c_xp_stats%notfound;
begin
mr_dba_segments := mt_dba_segments(mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name);
msg('Segment informations retrieved from memory structure', DEBUG, m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name, m_xp_session_name);
begin
actual_db_block_changes := nvl(mt_segment_statistics(mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name).value, 0);
exception
when no_data_found then
actual_db_block_changes := 0;
end;
msg('Real time block changes retrieved from memory structure', DEBUG, m_owner, mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name, m_xp_session_name);
diffBlocksChanged := ABS(actual_db_block_changes - nvl(mc_xp_stats.block_changes_when_analyzed, 0));
if (mc_xp_stats.segment_type = 'TABLE')or((mc_xp_stats.segment_type = 'TABLE PARTITION')) then
percBlocksChanged := calcPercForBlockChanges(percForTables, mr_dba_segments.blocks, logBaseTables, mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name, m_xp_session_name, m_owner);
elsif (mc_xp_stats.segment_type = 'INDEX')or(mc_xp_stats.segment_type = 'INDEX PARTITION')then
percBlocksChanged := calcPercForBlockChanges(percForIndexes, mr_dba_segments.blocks, logBaseIndexes, mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name, m_xp_session_name, m_owner);
else
msg('Segment type is ' || mc_xp_stats.segment_type ||
', unable to determine the percentual gap', ERROR, m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
end if;
msg('Segment type is ' || mc_xp_stats.segment_type || ', percentual is '||
percBlocksChanged, INFO,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
requiredBlocksForStats := percBlocksChanged * mr_dba_segments.blocks / 100;
msg('Current Block Changed:' || actual_db_block_changes||cr
||', Block Changed since last analyzed:'||nvl(mc_xp_stats.block_changes_when_analyzed, 0)||cr||
', abs(Current Block Changed - Block Changed since last analyzed ):'|| diffBlocksChanged||cr||
', Perc of Blocks to be Changed:'||percBlocksChanged ||cr||
', Total Blocks now for segment:'||mr_dba_segments.blocks||cr||
', Required Blocks to take Stats:'||requiredBlocksForStats,INFO,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
begin
m_just_inserted := nvl(mt_segment_statistics(mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'
||mc_xp_stats.partition_name).just_inserted, 0);
exception
when no_data_found then
m_just_inserted := 0;
end;
msg('Just_insert for segment is '|| m_just_inserted, debug, m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'
||mc_xp_stats.partition_name, m_xp_session_name);
tNow := sysdate;
if (m_just_inserted>0) then
--*SE E' UN NUOVO SEGMENTO, GLI PRENDO LA DATA DI STATISTICA DA CATALOGO
begin
select last_analyzed into realTimeLastAnalyzed from XPV_REAL_TIME_LAST_ANALYZED
where owner = mc_xp_stats.owner and segment_name = mc_xp_stats.segment_name and
nvl(partition_name, ' ') = nvl(mc_xp_stats.partition_name, ' ');
exception
when others then
msg('Exception while retrieving last_analyzed from XPV_REAL_TIME_LAST_ANALYZED',
ERROR, m_owner, mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'
||mc_xp_stats.partition_name, m_xp_session_name);
realTimeLastAnalyzed := null;
end;
msgRealTimeLastAnalyzed := 'Based on system catalog, the segment was last analyzed ';
if realTimeLastAnalyzed is null then
msgRealTimeLastAnalyzed := msgRealTimeLastAnalyzed || ' never before';
else
msgRealTimeLastAnalyzed := msgRealTimeLastAnalyzed || to_char(realTimeLastAnalyzed, 'dd/mm/yyyy hh24.mi.ss');
end if;
msg(msgRealTimeLastAnalyzed, debug, m_owner, mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'
||mc_xp_stats.partition_name, m_xp_session_name);
else
realTimeLastAnalyzed := null;
end if;
will_take_stats := 0;
if instance_startup > mc_xp_stats.last_check_date then
msg('Instance was started ('||to_char(instance_startup, 'dd/mm/yyyy hh24.mi.ss')||') after last segment check('||
mc_xp_stats.last_check_date ||'), skipping statistis in any case', INFO, m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
will_take_stats := -1;
end if;
-- if (will_take_stats = 0)and(m_just_inserted > 0) then
-- msg('The segment has just been inserted, stats will never be taken', INFO,m_owner,
-- mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
-- will_take_stats := -1;
-- end if;
if (will_take_stats = 0)and(mc_xp_stats.block_changes_when_analyzed is null) then
msg('There is not a last value of block changes for comparison, stats may be taken', INFO,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
will_take_stats := 1;
end if;
if (will_take_stats = 0)and(diffBlocksChanged >= requiredBlocksForStats) then
msg('The difference of blocks changed('|| actual_db_block_changes ||' - ' || nvl(mc_xp_stats.block_changes_when_analyzed, 0) ||
' = '|| diffBlocksChanged ||'), as an absolute value, is greater than the required value calculated, stats may be taken', INFO,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
will_take_stats := 1;
end if;
if (will_take_stats = 0)and(m_just_inserted >0)and(realTimeLastAnalyzed is null)then
msg('The segment is new and has never been analyzed, by querying system catalog', INFO,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
will_take_stats := 1;
end if;
if will_take_stats = 0 then
msg('No conditions have been applied, stats will not be taken by default', INFO,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
will_take_stats := -1;
end if;
if will_take_stats = 1 then
msg('Stats will be taken', INFO, m_owner, mr_dba_segments.name, m_xp_session_name);
end if;
msg('Updating memory record of dba_segments', DEBUG, m_owner, mr_dba_segments.name, m_xp_session_name);
mr_dba_segments.rowidForXp_stats := mc_xp_stats.rowid;
mr_dba_segments.block_changes_when_analyzed := actual_db_block_changes;
mr_dba_segments.curr_db_block_changes := actual_db_block_changes;
mr_dba_segments.stats_date := tNow;
mr_dba_segments.last_check_date := tNow;
mr_dba_segments.just_inserted := m_just_inserted;
msg('Just_inserted has been stored in memory as ' || mr_dba_segments.just_inserted, debug, m_owner, mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name, m_xp_session_name);
mr_dba_segments.last_db_block_changes := mc_xp_stats.curr_db_block_changes;
msg('Memory record of dba_segments updated', DEBUG, m_owner, mr_dba_segments.name, m_xp_session_name);
if will_take_stats > 0 then
mr_dba_segments.will_take_stats := true;
mr_dba_segments.analyzed_in_last_session := 1;
mt_dba_segments(mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name) := mr_dba_segments;
else
mr_dba_segments.will_take_stats := false;
mr_dba_segments.analyzed_in_last_session := 0;
mt_dba_segments(mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||
mc_xp_stats.partition_name) := mr_dba_segments;
end if;
exception
when others then
msg('Exception while processing segment : ' ||sqlerrm(sqlcode), ERROR,m_owner,
mc_xp_stats.owner||'.'||mc_xp_stats.segment_name||'.'||mc_xp_stats.partition_name,
m_xp_session_name);
if m_stop_on_exception then
raise;
end if;
end;
fetch c_xp_stats into mc_xp_stats;
end loop;
close c_xp_stats;
msg('Calculating the number of total blocks to be analyzed', DEBUG, m_owner, null, m_xp_session_name);
i := mt_dba_segments.FIRST; -- get subscript of first element
WHILE i IS NOT NULL LOOP
mr_dba_segments := mt_dba_segments(i);
if mr_dba_segments.will_take_stats then
totBlocksToAnalyze := totBlocksToAnalyze + mr_dba_segments.blocks;
totObjectsToAnalyze := totObjectsToAnalyze + 1;
end if;
i := mt_dba_segments.NEXT(i); -- get subscript of next element
END LOOP;
msg(totBlocksToAnalyze || ' blocks will be analyzed in this session', INFO, m_owner, null, m_xp_session_name);
--**************************
--* AGGIORNAMENTO XP_STATS *
--**************************
rindexObjectsToAnalyze := dbms_application_info.set_session_longops_nohint;
sofarObjectsToAnalyze := 0;
rindexBlocksToAnalyze := dbms_application_info.set_session_longops_nohint;
sofarBlocksToAnalyze := 0;
msg('Cicling memory table for stats', DEBUG, m_owner, null, m_xp_session_name);
i := mt_dba_segments.FIRST; -- get subscript of first element
WHILE i IS NOT NULL LOOP
msg('Retrieving memory record '|| i, debug, m_owner, i, m_xp_session_name);
mr_dba_segments := mt_dba_segments(i);
msg('Memory record retrieved '|| i, debug, m_owner, mr_dba_segments.name, m_xp_session_name);
msg('Just_inserted for memory record is '||mr_dba_segments.just_inserted, debug, m_owner, mr_dba_segments.name, m_xp_session_name);
if mr_dba_segments.will_take_stats then
sofarObjectsToAnalyze := sofarObjectsToAnalyze + 1;
sofarBlocksToAnalyze := sofarBlocksToAnalyze + mr_dba_segments.blocks;
dbms_application_info.set_session_longops(rindex=>rindexBlocksToAnalyze,
slno=>slnoBlocksToAnalyze, op_name=>'XP-Stat, blocks view',
target=>objBLocksToAnalyze, context=>0,
sofar=>sofarBlocksToAnalyze, totalwork=>totBlocksToAnalyze,
target_desc=>'Schema ' || m_owner ||', '|| totObjectsToAnalyze ||' segm. to analyze',
units=>'Blocks');
if mr_dba_segments.segment_type in ('TABLE', 'TABLE PARTIION') then
cascade_stats := mr_dba_segments.blocks <= max_blocks_to_force_cascade;
msg('Segment is a table or a table partition, force cascade is '||boolToString(cascade_stats)||', because block limit to force cascade is '||max_blocks_to_force_cascade||
' and total blocks for segment is '||mr_dba_segments.blocks, INFO, m_owner, mr_dba_segments.name, m_xp_session_name);
else
cascade_stats := false;
end if;
--se la tabella e partizionata e questa e la prima partizione per la tabella,
--allora prendo le statistiche senza specificare la partizione con granularity global
if(not mr_dba_segments.partition_name is null)and(length(mr_dba_segments.partition_name)>0) then
--verifico che questo non sia gia stato fatto
begin
mr_part_tables_analyzed := mt_part_tables_analyzed(mr_dba_segments.owner||'.'||mr_dba_segments.segment_name);
exception
when no_data_found then
msg('Taking global stats for table ', warning, m_owner, mr_dba_segments.name, m_xp_session_name);
takeStatsForObject(mr_dba_segments.owner, mr_dba_segments.segment_name,
null,
mr_dba_segments.segment_type, percentual_sample, m_degree,
m_simulation_only, m_xp_session_name, 'GLOBAL');
mt_part_tables_analyzed(mr_dba_segments.owner||'.'||mr_dba_segments.segment_name).owner := mr_dba_segments.owner;
mt_part_tables_analyzed(mr_dba_segments.owner||'.'||mr_dba_segments.segment_name).table_name := mr_dba_segments.segment_name;
end;
end if;
if(not mr_dba_segments.partition_name is null)and(length(mr_dba_segments.partition_name)>0) then
m_granularity := 'PARTITION';
else
m_granularity := 'DEFAULT';
end if;
msg('Taking stats for segment, granularity is ' || m_granularity, warning, m_owner, mr_dba_segments.name, m_xp_session_name);
takeStatsForObject(mr_dba_segments.owner, mr_dba_segments.segment_name,
mr_dba_segments.partition_name,
mr_dba_segments.segment_type, percentual_sample, m_degree,
m_simulation_only, m_xp_session_name, m_granularity);
update xp_stats set
block_changes_when_analyzed = mr_dba_segments.block_changes_when_analyzed,
curr_db_block_changes = mr_dba_segments.curr_db_block_changes,
stats_date = sysdate,
last_check_date = mr_dba_segments.last_check_date,
analyzed_in_last_session = mr_dba_segments.analyzed_in_last_session,
just_inserted = mr_dba_segments.just_inserted,
curr_blocks = mr_dba_segments.blocks,
xp_session_name = m_xp_session_name,
last_db_block_changes = mr_dba_segments.last_db_block_changes,
h_analyzed_in_last_session = 0
where rowid = mr_dba_segments.rowidForXp_stats;
else
msg('Stats will not be taken', INFO, m_owner, mr_dba_segments.name, m_xp_session_name);
update xp_stats set
--block_changes_when_analyzed = actual_db_block_changes,
curr_db_block_changes = mr_dba_segments.curr_db_block_changes,
--stats_date = tNow,
last_check_date = mr_dba_segments.last_check_date,
analyzed_in_last_session = mr_dba_segments.analyzed_in_last_session,
just_inserted = mr_dba_segments.just_inserted,
curr_blocks = mr_dba_segments.blocks,
xp_session_name = m_xp_session_name,
last_db_block_changes = mr_dba_segments.last_db_block_changes,
h_analyzed_in_last_session = 0
where rowid = mr_dba_segments.rowidForXp_stats;
end if;
if SQL%rowcount >0 then
msg('xp_stats table updated', INFO, m_owner, mr_dba_segments.name, m_xp_session_name);
else
msg('No matching on where clause while updating segment on xp_stats table', ERROR,m_owner,
mr_dba_segments.name, m_xp_session_name);
end if;
--***************
--* C O M M I T *
--***************
commit;
i := mt_dba_segments.NEXT(i); -- get subscript of next element
END LOOP;
msg('Cicling memory table for stats terminated', DEBUG, m_owner, null, m_xp_session_name);
calculateHistograms(m_owner, percentual_sample, m_degree, m_simulation_only,
m_stop_on_exception, m_xp_session_name);
msg('Procedure completed, '||totBlocksToAnalyze||' blocks analyzed.',
ALWAYS, m_owner, null, m_xp_session_name);
DBMS_APPLICATION_INFO.SET_ACTION(action_name =>'...done');
exception
when others then
msg(sqlerrm(sqlcode), ERROR, m_owner, null, m_xp_session_name);
DBMS_APPLICATION_INFO.SET_ACTION(action_name =>'...done');
raise;
end;
function getLogForSegment(m_segment varchar2, m_session varchar2 default null,
out_to_console boolean default false, logDate boolean default false) return varchar2 is
cursor c(m_segment varchar2, m_session varchar2) is
select * from xp_stat_log where segment like upper(m_segment)
and xp_session_name = decode(m_session, null, xp_session_name, upper(m_session))
order by prog;
mc c%rowtype;
result varchar2(32767);
newString varchar2(500);
i integer;
begin
open c(m_segment, m_session);
fetch c into mc;
loop
exit when c%notfound;
if (not out_to_console)and(length(result) > 0) then
result := result || cr;
end if;
if (logDate) then
newString := to_char(mc.data, 'yyyy/mm/dd hh24.mi.ss') || ':';
else
newString := '';
end if;
newString := newString || mc.log_level|| ': ' || mc.msg;
if (not out_to_console) then
result := result || newString;
else
outLongString(newString);
end if;
fetch c into mc;
end loop;
close c;
if (not out_to_console)then
return result;
else
return 'Output to console';
end if;
end;
end xp_stat;
/
|
IBM AIX
file xp_take_stats.sh
#!/bin/ksh
#
# script di lancio xp_stat - calcolo statistiche
#
export PATH=/bin:/usr/bin:/etc
export ORACLE_BASE=/home/oracle
unset ORACLE_SID
unset ORACLE_HOME
ORATAB=/etc/oratab
USAGE=' '
p_sid=$1
p_schema=$2
p_launch_notes=$3
if [[ "$p_sid" = "" ]]; then
echo "Wrong parameters: $*"
echo "Usage: $USAGE"
exit 99
fi
if [[ "$p_schema" = "" ]]; then
echo "Wrong parameters: $*"
echo "Usage: $USAGE"
exit 99
fi
cat $ORATAB | while read LINE
do
case $LINE in
\#*) ;; # comment-line in oratab
*)
# check if the sid parameter is in
if [[ "`echo $LINE | awk -F: '{print $1}' -`" = "$p_sid" ]] ; then
ORACLE_HOME=`echo $LINE | awk -F: '{print $2}' -`
export ORACLE_HOME
# if I have found a valid ORACLE_SID then I export it
export ORACLE_SID=$p_sid
fi
esac
done
if [[ "$ORACLE_HOME" = "" ]] ; then
echo "Sid not in $ORATAB !"
echo "Usage: $USAGE"
exit 99
fi
$ORACLE_HOME/bin/sqlplus /nolog << EOF
set serveroutput on
connect / as sysdba;
begin
system.xp_stat.takeStats(m_owner =>'$p_schema',
percentual_sample =>49,
m_degree => 1,
percForTables =>100,
percForIndexes =>100,
logBase => 1.2,
m_minimalLogLevel =>system.xp_stat.INFO,
m_truncateLogTable =>false,
m_simulation_only =>false,
m_stop_on_exception =>false,
m_log_retention_days => 2,
m_launch_notes => '$p_launch_notes');
end;
/
exit;
EOF
exit
|
Assuming VPO is a database user, from command line:
./xp_take_stats.sh pvgh1 VPO
Update xp_stats table with analyzed date with catalog dateupdate xp_stats x set stats_date = (select last_analyzed from xpv_real_time_last_analyzed where owner = x.owner and segment_name = x.segment_name and nvl(partition_name, ' ') = nvl(x.partition_name, ' ')); |
Quick activity log report since yesterdayselect * from xp_stat_log where log_level > 1 and trunc(data) in (trunc(sysdate), trunc(sysdate - 1)) order by prog desc; |
All segments ordered by last analyzed dateselect * from xp_stats order by NVL(stats_date, to_date(1,'yyyy')) desc; |
All segments analyzed in last sessionselect * from xp_stats order by analyzed_in_last_session desc; |
All segments ordered by last analyzed date for histogramsselect * from xp_stats order by NVL(h_last_date, to_date(1,'yyyy')) desc;
|
All stats taken in a periodselect * from xp_stat_log
where data >= to_date('31/05/2004 6.00.00', 'dd/mm/yyyy hh24.mi.ss')
and data <= to_date('01/06/2004 8.04.58', 'dd/mm/yyyy hh24.mi.ss')
and msg like '%Stats will be%'
order by prog asc; |
| See all log history for a segment set serveroutput on size 50000; declare dummy varchar2(50); begin dummy := xp_stat.getLogForSegment(m_segment=>'VPO.VPO045_VPOV41_FK_I.', m_session => null, out_to_console=> TRUE, logDate => true); end;For last session only select SEGMENT_LOG from: select * from xpv_stats where segment_name = 'ADEMP_ALLEGATI' and owner='VPO'; |
Take stats again next time, for the segments analyzed in a periodupdate xp_stats set block_changes_when_analyzed = -1000000 where owner||'.'||segment_name||'.'||partition_name in (
select distinct segment from xp_stat_log
where data >= to_date('03/06/2004 15.00.00', 'dd/mm/yyyy hh24.mi.ss')
and data <= to_date('03/06/2004 15.50.00', 'dd/mm/yyyy hh24.mi.ss')
and msg like '%Stats will be%'); |
See how many actual bytes were to be analyzed in a sessionselect count(*) obj_to_analyze, sum(bytes) bytes_total, sum(bytes)/1024/1024 MB_total, sum(bytes)/1024/1024/1024 GB_total, sum(bytes)/1024/1024/1024/1024 TB_total from ( select segment, bytes from xp_stat_log, dba_segments s where xp_session_name = 'DD761D33918F30D0E0330AB4400F30D0' and msg like 'Stats will be taken' and s.owner||'.'||segment_name||'.'||partition_name = segment order by prog asc ) |
A usefull way to determine stats params begin; xp_stat.PRINTSAMPLEPERCFORBLOCKCHANGES(100, 2, 1.2); end; --A 2 blocks segment will only be analyzed when all its blocks will be changed, while for a --largest segment a smaller percentual of changed blocks will be needed to take stats |
Install and configure packages and environment for custom Log Miner procedures Log Mining - Tips