mercoledì 25 marzo 2015

RDBMS ORACLE- Stale Statistics III

Come detto negli altri due post per eliminare le statistiche di tipo STALE occorre ricalcolarle.
Purtroppo non è detto che la tabella a livello globale risulti essere NO STALE una volta ricompilate le partizioni e/o le sottopartizioni, occorre quindi esplicitamente effettuare il calcolo delle statistiche della tabella.
A questo punto uno può dire ma le ho fatte prima le statistiche che faccio come i cani che ricorrono la propria coda?
No mentre prima le statistiche erano state fatte a livello di partizioni e sottopartizioni in questo caso devono essere eseguite a livello Globale.
Di seguito come individuarle e come eseguirle:

for t in (
          SELECT C.OWNER,C.TABLE_NAME
            FROM
                (SELECT A.OWNER,A.TABLE_NAME ,A.SAMPLE_SIZE
                   FROM DBA_TAB_STATISTICS A,DBA_TABLES B
                  WHERE A.OWNER=v_owner AND A.STALE_STATS='YES'
                    AND A.OWNER=B.OWNER AND A.TABLE_NAME=B.TABLE_NAME
                    AND B.PARTITIONED='YES' AND A.OBJECT_TYPE='TABLE') C,
                DBA_TAB_STATISTICS D
            WHERE  C.OWNER=D.OWNER AND C.TABLE_NAME=D.TABLE_NAME
            AND C.TABLE_NAME = <v_table_name> AND D.OBJECT_TYPE='PARTITION'
            GROUP BY C.OWNER,C.TABLE_NAME                
  )loop

            v_cmd:='BEGIN DBMS_STATS.GATHER_TABLE_STATS(
                                     OwnName => :v_owner,
                                     TabName => :x_table_name,
                                     Granularity => ''GLOBAL'',
                                     Degree => 2,
                                     Cascade => TRUE);
                      END;';
           dbms_output.put_line('TABLE_NAME:'||x.table_name);
           execute immediate v_cmd using in t.owner,t.table_name;               

   end loop;


In questo modo eseguiamo le statistiche su tutte le tabelle partizionate/sottopartizionate.

OWM - RDBMS ORACLE 11G - Come aggiungere una colonna ad una tabella Versionata

Una volta che una tabella viene versionata, può nascere la necessità di modificarla aggiungendo delle nuovo colonne. Come si fa in questo caso a modificare una tabella versionata senza sversionarla?
Semplice utilizziamo i package messi a disposizione da OWM, peccato che in alcuni casi ed in particolare per la versione 11g possono essere soggetti ad alcuni bug.

CASO DI TEST: Abbiamo una tabella avente la seguente struttura, indicata di seguito, a cui dobbiamo aggiungere 3 colonne not null.



A questo punto aggiungiamo le 3 colonne utilizzando come dice la documentazione la procedura BEGINDDL/COMMITDDL eseguendo questi comandi:

BEGIN DBMS_WM.BEGINDDL('T4967.AGGRRULECUBE');  END;
alter table T4967.AGGRRULECUBE_LTS ADD("RULE_PARAMETER" VARCHAR2(2000) NOT NULL);
alter table T4967.AGGRRULECUBE_LTS ADD("CONTEXTID" VARCHAR2(60) NOT NULL);
alter table T4967.AGGRRULECUBE_LTS ADD("CUBESTATTYPE" VARCHAR2(20) NOT NULL);
BEGIN DBMS_WM.COMMITDDL('T4967.AGGRRULECUBE');  END;


Facendo in questo modo, avremo subito il seguente errore nel momento in cui effettueremo la COMMITDDL:

...
BEGIN DBMS_WM.COMMITDDL('T4967.AGGRRULECUBE');  END;
Report error -
ORA-00904: "RULE_PARAMETER": identificativo non valido
ORA-06512: a "WMSYS.LT", line 12487
ORA-06512: a line 1
00904. 00000 -  "%s: invalid identifier"
*Cause:   
*Action:



Allora continuiamo riportando tutto a prima della BEGINDDL e proviamo un altro approccio non più tutte le operazioni insieme ma invece le dividiamo:

BEGIN DBMS_WM.BEGINDDL('T4967.AGGRRULECUBE');  END;
alter table T4967.AGGRRULECUBE_LTS ADD("RULE_PARAMETER" VARCHAR2(2000) NOT NULL);
BEGIN DBMS_WM.COMMITDDL('T4967.AGGRRULECUBE');  END;


Anche in questo caso niente da fare in fase di COMMIT avremo lo stesso errore indicato sopra. Allora procediamo ancora spacchettando il comando visto sopra nei seguenti:

BEGIN DBMS_WM.BEGINDDL('T4967.AGGRRULECUBE');  END;
alter table T4967.AGGRRULECUBE_LTS ADD("RULE_PARAMETER" VARCHAR2(2000) );
BEGIN DBMS_WM.COMMITDDL('T4967.AGGRRULECUBE');  END;
BEGIN DBMS_WM.BEGINDDL('T4967.AGGRRULECUBE');  END;
alter table T4967.AGGRRULECUBE_LTS MODIFY("RULE_PARAMETER"  NOT NULL);
BEGIN DBMS_WM.COMMITDDL('T4967.AGGRRULECUBE');  END;


blocco anonimo completato
table T4967.AGGRRULECUBE_LTS modificato.
blocco anonimo completato
blocco anonimo completato
table T4967.AGGRRULECUBE_LTS modificato.
blocco anonimo completato


Questa volta sembrerebbe tutto ok, peccato che se guardiamo la describe della tabella il nuovo campo aggiunto non risulta essere NOT NULL ma ancora NULLABLE.






Come si spiega il tutto? Semplice abbiamo un piccolo BUG fissato nella 12c, come lo risolviamo?
Effettuiamo l'ultima operazione di BEGINDDL/COMMITDDL da una sessione differente e come magia anche se nella describe il campo apparirà sempre NULLABLE il sw però avrà creato  un  check constraint di NOT NULL sulla tabella.

BEGIN DBMS_WM.BEGINDDL('T4967.AGGRRULECUBE');  END;
alter table T4967.AGGRRULECUBE_LTS MODIFY("RULE_PARAMETER"  NOT NULL);
BEGIN DBMS_WM.COMMITDDL('T4967.AGGRRULECUBE');  END;


...

blocco anonimo completato
table T4967.AGGRRULECUBE_LTS modificato.
blocco anonimo completato






Occhio però ... se lo fate due volte di seguito verranno creati due check constraint che fanno la stessa cosa come in figura sopra.