MAX/MIN con KEEP (DENSE_RANK FIRST/LAST ORDER BY …)

venerdì 5 maggio 2017 alle 05:23 | Pubblicato su 11g, 12c, Diario, SQL | Lascia un commento

Devo dire che mi mancava questo aspetto del mio lavoro, trovare soluzioni a problemi, scoprendo ed approfondendo nuove cose. Partendo dalle fonti che ho trovato per il mio post precedente (al riguardo ho aggiunto al “blogroll” l’interessante blog di Stewart Ashton, dal quale sono partito oggi) ho avuto modo di leggere a approndire un post che ha cinque anni, cinque anni in cui non ricordo di aver mai visto l’operatore di cui parla. La cosa effettivamente molto bizzarra è che la sezione KEEP… oggetto di quel post non viene menzionata nella documentazione in corrispondenza delle funzioni MIN e MAX, neanche nella sezione dedicata alle funzioni analitiche (anche perché non sembra rientrare in quella categoria) ma come indicato da Rob Van Vijk nel post viene descritta (sommariamente direi) alle funzioni FIRST e LAST  che sono in realtà solo una parte della clausola KEEP. I link alla documentazione Oracle riportati nel post del 2012 nel frattempo sono stati invalidati da un cambiamento fatto da Oracle, c’è sicuramente lo stesso problema anche in molti miei vecchi post.

Ho poco da aggiungere all’ottimo post di Rob Van Vijk che riporta un semplice caso di test e le sue prove. Io direi che l’utilizzo delle funzioni MAX/MIN(..) KEEP (DENSE_RANK FIRST/LAST ORDER BY ..) mi pare possa snellire la query nelle casistiche interessate rispetto all’uso della funzione analitica. Ovviamente non prendo neanche in considerazione l’approccio con il NOT EXIST che aveva senso il secolo scorso prima che fossero introdotte le funzioni analitiche

CAST e MULTISET

mercoledì 3 maggio 2017 alle 03:33 | Pubblicato su 11g, 12c, Diario, SQL | Lascia un commento

Oggi partendo da una procedura commissionatami  che doveva fare un aggiornamento dei dati sono arrivato ad approfondire un operatore che forse ho visto di sfuggita in passato ma certamente non ho usato ne’ capito, ragion per cui oggi, avendo un attimo di tempo ho deciso di dedicarmici.

Il punto di partenza è una organizzazione dei dati di cui ignoro le motivazioni alla base ma che mi sembra, in un database relazionale, poco corretta; si tratta infatti di un campo di tipo VARCHAR2 che contiene degli id numerici che fanno riferimento ad un campo di un’altra tabella separati da una virgola. Concedo il beneficio del dubbio ma non ho capito perché non si è usato una tabella di relazione come in un database relazionale si dovrebbe fare. Il fatto è che a livello di SQL fare anche una banale join per estrapolare i dati diventa una cosa assai complicata.  Per cercare di spiegarmi cerco di riportare un caso di test:

create table T1 (
 t1_id number,
 t1_desc varchar2(30)
);
create table T2 (
 t2_id number,
 t2_t1ids varchar2(90),
 t2_desc varchar2(30)
);

insert into T1 values (1,'a');
insert into T1 values (2,'b');
insert into T1 values (3,'c');
insert into T1 values (4,'d');
insert into T2 values (1,'1,2','uno');
insert into T2 values (2,'2,3,4','due');
insert into T2 values (3,'1,4','tre');
insert into T2 values (4,'4','quattro');

Ora sul campo T2.T2_T1IDS ho degli id separati da virgola in un campo di tipo stringa che dovrebbero fare riferimento al campo T1.T1_ID. In un database relazionale ci sarebbe una tabella T3 che come struttura avrebbe due campi, uno che punta a T1.T1_ID e uno che punta a T2.T2_ID, se poi voglio estrarre i dati li ricostruisco con una join sulle tre tabelle; qui non è così facile, magari a me sfugge qualcosa ma di sicuro se scrivo questo non va bene:

SVILUPPO@svil112 > select * from t2 join t1 on (t1_id in t2_t1ids);
select * from t2 join t1 on (t1_id in t2_t1ids)
 *
ERROR at line 1:
ORA-01722: invalid number

Io sono giunto alla conclusione che bisogna in qualche modo fare un parsing del campo T2.T2_T1IDS. In passato ho fatto delle procedurine per fare una cosa simile ma siccome non mi piacevano molto e mi sembravano più complesse del necessario ho pensato di fare una nuova ricerca su internet, in pratica ho cercato una funzione inversa rispetto a LISTAGG e sono arrivato a questa discussione su ORAFAQ. Qui ho trovato due interessanti soluzioni che ho deciso di approfondire e capire e questo è il motivo di questo post. La prima, applicata al mio caso di test dovrebbe essere più o meno così:

SVILUPPO@svil112 > with test as
 2 (select * from t2 where t2_desc='due' )
 3 select * from
 4 (select t2_id,regexp_substr(t2_t1ids, '[^,]+', 1, level) t1id
 5 from test
 6 connect by level <= length(regexp_replace(t2_t1ids, '[^,]+')) + 1)
 7 join t1 on t1_id=t1id;

 T2_ID T1ID T1_ID T1_DESC
---------- ---- ---------- ------------------------------
 2 2 2 b
 2 3 3 c
 2 4 4 d

Da quello che ho capito io la funzione regexp_substr(t2_t1ids, ‘[^,]+’, 1, level) prende una occorrenza di tutto ciò che non contiene al suo interno una virgola, “level” indica quale occorrenza, quindi la sottoquery restituisce un record per ogni id nel campo t2_t1ids.  Nella discussione viene fatto un intervento che spiega come quella prima soluzione non funziona nel caso di più record estratti dalla query nella sezione “WITH”, infatti:

SVILUPPO@svil112 > with test as
 2 (select * from t2 where t2_desc='due' or t2_desc='tre' )
 3 select * from
 4 (select t2_id,regexp_substr(t2_t1ids, '[^,]+', 1, level) t1id
 5 from test
 6 connect by level <= length(regexp_replace(t2_t1ids, '[^,]+')) + 1)
 7 join t1 on t1_id=t1id;

  T2_ID T1ID T1_ID T1_DESC
---------- ---- ---------- ------------------------------
 3 1 1 a
 2 2 2 b
 2 3 3 c
 2 3 3 c
 2 4 4 d
 3 4 4 d
 2 4 4 d
 2 4 4 d
 3 4 4 d
 2 4 4 d

La “connect by level<….” provoca una moltiplicazione dei record nel risultato che non va bene. Anche qui avrei da approfondire perché confesso che non ho chiarissimi alcuni dettagli del funzionamento delle query gerarchiche. Se non ho capito male al primo livello ci sono tutti i valori della tabella diciamo n, al secondo livello per ogni valore ci sono  n figli e così via; qui la cosa si complica e richiederà altri approfondimenti.

La variante suggerita per risolvere il problema nel caso più generico è un po’ più complessa ed applicata al mio caso di test dovrebbe essere così:

SVILUPPO@svil112 > WITH test AS
 2 (SELECT * FROM t2 WHERE t2_desc='due' or t2_desc='tre' )
 3 SELECT * FROM
 4 (SELECT t2_id,REGEXP_SUBSTR(t2_t1ids, '[^,]+', 1, b.column_value) t1id
 5 FROM test a CROSS JOIN
 6 TABLE
 7 (
 8 CAST
 9 (
 10 MULTISET
 11 (
 12 SELECT LEVEL FROM DUAL
 13 CONNECT BY LEVEL <= REGEXP_COUNT(a.t2_t1ids, '[^,]+')
 14 )
 15 AS SYS.odciNumberList
 16 )
 17 ) b
 18 )
 19 join t1 on t1_id=t1id;

T2_ID T1ID T1_ID T1_DESC
---------- ---- ---------- ------------------------------
 2 2 2 b
 2 3 3 c
 2 4 4 d
 3 1 1 a
 3 4 4 d

Così mi pare corretta, seppur un po’ lunga.

Nell’ultima soluzione proposta ci sono alcune cose che io non conoscevo molto bene, la prima è l’utilizzo della sintassi CROSS JOIN che serve a generare un prodotto cartesiano con la sintassi ANSI della JOIN. La seconda cosa è quello che sembra un operatore MULTISET, in realtà è parte dell’operatore CAST. Come dice la documentazione MULTISET informa Oracle di prendere il risultato della sottoquery e restituire un valore “collection”. Questa “collection” viene convertita nel tipo predefinito SYS.odciNumberList che è documentato qui. A suo volta questo tipo può essere dato in pasto all’operatore TABLE e così di fatto la lista di valori è trasformata al volo in una tabella.

Non credo e spero di dover ritornare su situazioni analoghe a questa, in ogni caso quando capiterà avrò pronto qui qualche appunto che mi aiuterà.

 

Riferimenti:

Tipi predefiniti (Database Data Cartridge Developer’s Guide 11.2) , per 12.1 qui.

OraFaq

 

P.S.

2017/05/04: credo valga la pena di riportare qui un altro post interessante che ho trovato oggi: https://stewashton.wordpress.com/2016/06/22/new-improved-in-lists/

SQL*Plus 12.2

giovedì 20 aprile 2017 alle 20:10 | Pubblicato su 12c, SQL, Varie | 1 commento
Tag:

Oggi ho provato a installare la versione 12.2 del nuovo instant client Oracle versione 12.2 sul mio pc aziendale con sistema operativo Win7. Non ci sono motivi particolari per cui ci sia la necessità di passare ad usare questa versione se non al puro scopo di testarla e tal proposito mi sono ricordato di un post di Mike Dietrich (anche perché l’ho letto ieri 🙂 ) dove si parla che una fra le novità di questa versione di SQL*Plus è la diversità di comportamento nel caricamento del file “login.sql”. Io normalmente uso sul mio pc una configurazione per cui lancio uno script .cmd che a sua volta chiama un’altro script che setta le opportune variabili d’ambiente, fra cui SQLPATH affinché punti a una directory dove trovo una serie di script di utilità (per molti dei quali vanno i ringraziamenti a Tanel Poder)  e l’utilissimo login.sql che imposta l’ambiente iniziale per SQL*Plus come garba a me. Con la nuova versione di SQL*Plus effettivamente l’esecuzione automatica di login.sql che si trova sotto il percorso puntato dalla variabile d’ambiente SQLPATH non funziona. Infatti il post di Franck Pachot cui fa riferimento Dietrich fa tutti i test dettagliati su ambiente Linux, peccato però che come scrive Dietrich alla fine del suo post:

On Windows please be aware of (credits to Tim Hall):

  • Bug 25804573SQL PLUS 12.2 NOT OBSERVING SQLPATH IN REGISTRY OR ENV VARIABLE FOR LOGIN.SQL

 

Ti pareva se su Winzoz non c’era qualche fastidio…

Sinceramente non mi è chiaro come aggirare il problema, la soluzione che ho adottato io sembra bruttina ma è l’unica che ho trovato in modo veloce: ho rinominato sqlplus.exe in sqlplus_orig.exe, ho creato un file sqlplus.cmd il cui contenuto è:

sqlplus_orig.exe %1 @login

Ora, prima ho provato a non rinominare il file .exe confidando che la logica di ricerca degli eseguibili mettesse prima i .cmd e dopo i .exe ma non sembra esssere così. La cosa che invece mi perplede abbastanza è il fatto che se metto @login.sql non funziona, @login si. Anche se invoco successivamente @login.sql non funziona, funziona se lo invoco con il percorso completo

SYSTEM@svil121 > @login.sql
SYSTEM@svil121 > @c:\oracle\conf\login.sql

PL/SQL procedure successfully completed.


Session altered.

Questa particolarità vale solo per il file login.sql, gli altri script funzionano sia che metta l’estensione  e sia che non la metta

 

 

Oracle Data Pump – parametri QUERY e EXCLUDE

giovedì 13 aprile 2017 alle 13:48 | Pubblicato su Diario | 1 commento

Oggi mi è capitato di dovermi cimentare con un esportazione di uno schema dati Oracle “selettiva”: per portare via un dump con schema e dati alleggerito. Non è la prima volta che mi capita ma questa volta avevo l’esigenza di introdurre diversi filtri sui dati e sugli oggetti. In realtà i filtri non erano particolarmente complessi ma sono incappato in un paio di particolarità che mi avevano gia messo in difficoltà altre volte ma che in tali occasioni avevo deciso di non approfondire rinunciando alla granularità dei filtri.

I parametri di Oracle Data Pump Export con cui ho lavorato sono QUERY, per filtrare i dati su alcune tabelle e EXCLUDE per escludere alcune tabelle che in realtà sono state introdotte come backup o prove o chissacosa nel tempo e che non avevo nessuna intenzione di portarmi dietro.

Query

il parametro query da manuale (11.2) prevede questa sintassi:

QUERY = [schema.][table_name:] query_clause

La parte “query_clause” è tipicamente la sezione “WHERE” di una query ma può essere qualunque clausola SQL, nel manuale riporta l’esempio di un “ORDER BY”. Su quest’ultima parte vado in fiducia perché ho avuto necessità solo di WHERE e solo quella ho provato.  Prima della query_clause è prevista come opzionale la specifica della tabella su cui applicare la clausola, se non viene specificata la clausola deve essere valida per tutte le tabelle esportate, quindi nella pratica deve riferire a qualche campo con un nome che si trova in tutte le tabelle esportate. Nel mio caso le tabelle esportate sono tante e il campo su cui filtrare ha sempre un nome diverso, quindi ho dovuto scrivere più occorrenze del parametro QUERY, una per ogni tabella, in questo modo:

QUERY=(tabella1:" WHERE t1campoa='a')
QUERY=(tabella2:" WHERE t2campoa='a')
QUERY=(tabella3:" WHERE t3campoa='a')
.....

 

Si possono tranquillamente mettere più occorrenze del parametro QUERY, naturalmente io uso un file di parametri, come consigliato anche dal manuale per non avere problemi di escape degli apici doppi. La cosa si complica se si vogliono clausole WHERE più complesse, qui mi limito a riportare il collegamento ad un ottimo post di Laurent Schneider che spiega come gestirli, un aiuto lo si trova anche fra i commenti.

Exclude

Questa la sintassi indicata sul manuale:

EXCLUDE=object_type[:name_clause] [, ...]

questo parametro mi ha fatto un po’ penare perché io avevo necessità di escludere tabelle il cui nome termina con “_O” oppure con “_BCK”.  Se avessi scritto:

EXCLUDE=TABLE:" LIKE '%_O'"

non avrebbe funzionato come volevo perché “_” in SQL è analogo a “%” e indica un carattere qualsiasi, quindi di fatto avrei escluso tutte le tabelle il cui nome termina con “O”. In SQL da lungo tempo (se non erro dalla versione 10 di oracle) si usare un carattere per fare l'”escape” quindi solitamente io scrivo:

SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME LIKE '%\_O' ESCAPE '\';

Ecco, scrivendo

EXCLUDE=TABLE:" LIKE '%\_O' ESCAPE '\' "

ottenevo l’errore:

ORA-39001: invalid argument value
ORA-39071: Value for EXCLUDE is badly formed.
ORA-01425: escape character must be character string of length 1

Confesso che al primo giro non ho letto con attenzione la terza riga dell’errore, quindi ho fatto un paio di tentativi ed ho affinato le mie ricerche su internet fin quando finalmente sono arrivato a questo post che nella sua parte finale da un lato mi ha confermato che la sintassi che usavo era corretta dall’altro mi ha fatto venire il dubbio che il mio problema fosse solo il carattere di escape scelto, quindi, prima ancora di cercare di capire come mai il mio “\” non gli piacesse l’ho sostituito con un “!” ed ho riprovato

EXCLUDE=TABLE:" LIKE '%!_O' ESCAPE '!' "

magicament ha funzionato.

Mi sono imposto di segnarmi questa cosa in modo da non scordarla più, dunque quale posto migliore se non un nuovo post qui!

 

Riferimenti:

  1. http://www.usn-it.de/index.php/2009/05/22/oracle-impdp-wildcard-hacking/
  2. http://laurentschneider.com/wordpress/2011/07/datapump-table-like-foo-or-like-bar.html

 

 

Campi varchar2 con stringhe vuote

mercoledì 7 ottobre 2015 alle 07:14 | Pubblicato su PL/SQL, SQL, Varie | Lascia un commento

Post molto sintetico:


set serveroutput on size unlimited

declare
a varchar2(10);
begin
a := '';
if (a is null) then dbms_output.put_line('empty = null');
else dbms_output.put_line('empty is not null');
end if;
if (a = '') then dbms_output.put_line('empty = empty');
else dbms_output.put_line('empty <> empty');
end if;
a := null;
if (a is null) then dbms_output.put_line('empty = null');
else dbms_output.put_line('empty is not null');
end if;
if (a = '') then dbms_output.put_line('empty = empty');
else dbms_output.put_line('empty <> empty');
end if;
end;

TEST@test112 > /
empty = null
empty <> empty
empty = null
empty <> empty

ORA-00600: internal error code, arguments: [13013]

martedì 13 gennaio 2015 alle 13:31 | Pubblicato su Diario | Lascia un commento

Oggi ho probabilmente trovato qualche postumo dei problemi di cui ho scritto ieri con ORA-00333. Stamattina uno dei database che ho ripristinato ieri era giu, a quanto pare il sistem monitor (SMON) si era suicidato a causa di ripetuti errori ORA-00600. Suppongo che l’errore venisse generato in seguito a una query eseguita credo per l’aggiornamento delle statistiche dell’ottimizzatore, la query in questione dai trace pare fosse una update sulla tabella SYS.MON_MODS$, di cui io per la verità non so nulla, se non che stando nello schema SYS potrebbe essere importante per la vita del mio database…

Lo strumento di ricerca degli errori ORA-00600 mi ha mandato alla nota 816784.1 che pare vecchiotta e nella descrizione dei vari codici cita le versioni dalla 8.0.3 alla 10.1, il che mi ha lasciato perplesso, però non trovando altro di più rilevante ho seguito le indicazioni di tale nota. Per fortuna la prima verifica, quella relativa all’integrità della tabella è andata liscia, segno che forse era l’indice ad essere corrotto. La seconda verifica (Analyze table <owner>.<table name> validate structure cascade online ; ) però, anziché darmi un codice ORA-1499 mi ha dato un bel ora-600 [kdsgrp1] che ripassando per lo strumento di ricerca degli errori ORA-00600 del supporto ORacle, secondo la nota 1332252.1 sembra dovuto alla stessa causa dell’errore da cui sono partito, quindi presumibilmente la corruzione di un indice sulla tabella. Ho provato allora a ricostruire l’indice, operazione tutto sommato semplice, anche se l’agire su una tabella di sistema mi metteva un po’ di ansia. Alla fine ho fatto anche un controllo con dbverify e pare che sia andato tutto a posto

Il mistero di ORA-00333

lunedì 12 gennaio 2015 alle 12:18 | Pubblicato su 11g, Backup and Recovery, Diario | 3 commenti

Un paio di nostri database server si appoggiano a una NAS, usando iscsi, per lo spazio disco. Uno è un server linux e l’altro window, entrambi hanno dei dischi iscsi su questa Nas esterna e su questi dischi ci sono dei database di sviluppo e test interni. Ogni tanto, per svariati motivi capita che la NAS ha un mancamento, in questa situazione quello che accade sulla macchina linux è che il filesystem, quanto la NAS si riprende, viene automaticamente rimontato in modalità read-only, cosa che naturalmente non piace ad Oracle. Sulla macchina Windows il disco sembra venga rimontato normalmente, ciò nonostante Oracle non la prende comunque bene.

Questa mattina è successo di nuovo, in precedenza è andata sempre abbastanza bene, sulla macchina linux basta fermare Oracle, smontare e rimontare in modalità read-only il disco e riavviare Oracle, sulla macchina Windows basta solo riavviare Oracle, fino ad oggi tali passi erano stato sufficienti. Stamattina però le cose sono andate storte, sulla macchina Windows i due database segnalavano in fase di apertura l’errore

ORA-00333: errore lettura redo log blocco 34873 conteggio 7758

Naturalamente cambiavano i numeri di “blocco” e “conteggio”, quello su linux data un errore di disallineamento dei controlfile:

ORA-00214: control file
‘/opt/oracle/storage/recovery_area/marte112/control02.ctl’ version 1093680
inconsistent with file ‘/opt/oracle/storage/data/marte112/control01.ctl’
version 1093666

Quest’ultimo problema l’ho  affrontato copiando il file con il numero di versione più alto sopra l’altro. Fatto ciò anche qui in fase di apertura del database ho ricevuto il messaggio:

ORA-00333: redo log read error block 55748 count 8192

Ho cercato di mantenere la calma e vedere cosa si poteva fare. Per due database avevo a disposizione un backup della notte prima, quindi ero abbastanza tranquillo, per l’altro non c’è backup per motivi di spazio e perché non è così importante. Ho fatto delle ricerce sull’errore, senza capire però effettivamente la sua origine, perché parrebbe dovuto al fatto che si sia corrotto un online redolog, però facendo una ricerca su internet si trova, anche sul forum Oracle come soluzione un recovery incompleto e la successiva apertura del database con l’opzione RESETLOGS. Messa così la cosa ha senso, si ferma il recovery senza applicare il redo contenuto negli online redo, che a quanto pare sono corrotti e si riesce a far ripartire il database perdendo solo quanto contenuto negli online redolog.

Le cose però non stanno proprio così, perché quello che ho fatto io è stato di applicare anche il redo degli online redolog:

SQL> recover database until cancel;
ORA-00279: change 10685641157734 generated at 01/11/2015 01:14:20 needed for
thread 1
ORA-00289: suggestion :
/opt/oracle/storage/recovery_area/MARTE112/archivelog/2015_01_12/o1_mf_1_28964_%
u_.arc
ORA-00280: change 10685641157734 for thread 1 is in sequence #28964

Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
/opt/oracle/storage/data/marte112/redo02.log
Log applied.
Media recovery complete.
SQL> alter database open;
alter database open
*
ERROR at line 1:
ORA-01589: must use RESETLOGS or NORESETLOGS option for database open

SQL> alter database open noresetlogs;
alter database open noresetlogs
*
ERROR at line 1:
ORA-00333: redo log read error block 55748 count 8192

 

Ecco, siccome questo era uno dei database di cui avevo il backup ho deciso di fare un piccolo azzardo, pensando non fosse tanto azzardato, ho cercato di aprire il database con l’opzione NORESETLOGS, così da vedere cosa succedeva. Il punto è che il mio recovery mi sembrava completo, non incompleto, perché aveva terminato da solo, non in seguito a un mio “CANCEL”, il redo che ho indicato era l’unico che dalla vista V$LOG risultava attivo e contenente la sequenza richiesta dalla procedura di recovery (gli altri due risultavano anche archiviati), quindi in questa fase Oracle è riuscito ad aprire e leggere l’online redolog senza problemi, senza darmi ORA-00333, come mai? Io non l’ho capito.

Torniamo adesso al mio azzardo/esperimento di aprire il database con l’opzione NORESETLOGS, i miei successivi tentativi sono stati questi:

SQL>  alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-01139: RESETLOGS option only valid after an incomplete database recovery

SQL> recover database until cancel;
ORA-10879: error signaled in parallel recovery slave
ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below
ORA-01152: file 1 was not restored from a sufficiently old backup
ORA-01110: data file 1: ‘/opt/oracle/storage/data/marte112/system01.dbf’

SQL> alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-01152: file 1 was not restored from a sufficiently old backup
ORA-01110: data file 1: ‘/opt/oracle/storage/data/marte112/system01.dbf’

 

Al che ho cominciato a preoccuparmi perché mi scocciava dover ripristinare tutto il backup. Al che ho deciso di fare un disperato tentativo, disperato perché per la verità senza cognizione di causa:

SQL>  recover database using backup controlfile until cancel;
ORA-00279: change 10685641181646 generated at 01/11/2015 03:06:33 needed for
thread 1
ORA-00289: suggestion :
/opt/oracle/storage/recovery_area/MARTE112/archivelog/2015_01_12/o1_mf_1_28964_%
u_.arc
ORA-00280: change 10685641181646 for thread 1 is in sequence #28964

Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
/opt/oracle/storage/data/marte112/redo02.log
Log applied.
Media recovery complete.
SQL> alter database open resetlogs;

Database altered.

 

Ho cioè deciso di provare il recovery incompleto aggiungendo l’opzione “using backup controlfile”, e mi è andata bene 🙂

Il mio controlfile era sempre lo stesso, non era stato ripristinato da un backup. Che cosa significhi veramente la clausola “using backup controlfile” non sono sicuro di averlo ancora capito bene, la migliore spiegazione che ho trovato è questa. Però mi sfugge cosa abbia fatto il mio primo tentativo si recovery… mi piacerebbe capirne di più

P.S.

naturalmente sugli altri due database è stato più semplice, è bastato usare subito  l’opzione RESETLOGS

Soluzioni di Virtualizzazione dei dati

giovedì 8 gennaio 2015 alle 08:21 | Pubblicato su cloud, Diario, Varie, virtualizzazione | Lascia un commento
Tag:

Negli ultimi tre/quattro anni sono stato molto pigro o forse solamente preso da altri impegni, sia lavorativi che extralavorativi, fatto sta che ho dedicato molto meno tempo di quanto non ne dedicassi prima all’approfondimento di nuove tematiche tecnologiche e al rimanere per quanto possibile informato sull’andamento della tecnologia almeno nel settore più vicino a quello in cui lavoro, quindi sintetizzando ai sistemi di gestione delle basi di dati. A peggiorare la situazione è arrivata sei mesi fa una batosta personale che oltre a mettere a dura prova il mio morale e le mie motivazioni ha ridotto ulteriormente il mio tempo libero a disposizione per questa attività di formazione continua. Oggi ho trovato il tempo per dedicarmi all’esplorazione degli articoli “non letti” presenti sulla mia sezione feedly, articoli che si sono accumulati ormai da mesi, anche se noto una scarsa attività.

Oggi ho letto questo articolo di Kyle Hailey intitolato “Top 3 criteria to choose a data virtualization solution”. Quando ho iniziato a leggerlo non avevo neanche idea di che cosa si intendesse  per “data virtualizzation solution”, man mano che leggevo l’articolo pensavo a quanto la tecnologia in questo campo deve essere avanzata in questi ultimi anni, praticamente senza che io me ne accorgessi. D’accordo, è un settore che effettivamente io per ora posso guardare solo da fuori, forse la mia azienda ancora non ha dimensioni tali da sentire l’esigenza o la necessità di questo tipo di soluzioni, anche se posso immaginare che andando le cose come sono andata negli ultimi anni tale esigenza potrà a breve sorgere. In ogni caso la letture di questo articolo è stata per me stimolante, anche se non entra in nessun dettaglio, fa un ottimo riassunto delle caratteristiche che ci si può aspettare di trovare e quindi ottenere oggi con questi sistemi di virtualizzazione dei dati, che in pratica estendono di molto il concetto di snapshot gia presente sulle SAN e su alcuni tipi di filesystem gia da anni. Hailey scrive che ci sono sistemi che permettono di fare dei “branch” dei dati, che tali branch possono essere fatti in modo efficente sia in termini di tempo che di spazio occupato, un po’ come facciamo normalmente con il sistema di gestione del codice sorgente ad esempio con Subversion.

In effetti anche nella mia piccola esperienza mi ritrovo con la problematica di avere più copie e versioni degli stessi dati, solitamente i database si moltiplicano, ambienti di sviluppo, di test, di integrazione, di UAT, di demo ecc. Questo viene gestito nel mio caso con dump di schemi di database Oracle che vengono creati e importati qua e la.

Si tratta di un argomento che ho trovato interessante, per questo ho voluto scriverne qualcosa, se non altro per tenere una traccia anche dell’interessante articolo di Kyle Hailey, se qualcuno mi dovesse chiedere qualcosa in futuro sui sistemi di virtualizzazione dati o CDM o CDV o DVA forse potrò dare una risposta diversa dal solito: “mai sentito prima ” 🙂

Ricerche case sensitive in Oracle 11gR2 e 12cR1

venerdì 22 agosto 2014 alle 22:03 | Pubblicato su 11g, 12c, Diario, Performance Tuning | Lascia un commento
Tag: , ,

Questo post è un aggiornamento del post “Database case sensitive su 10.2.0.3“,  aggiornamento necessario, essendo il post risalente ad oltre sette anni fa. In realtà ho fatto qualche test in questi sette anni ma non ben formalizzato, quando poi mi è stato chiesto per l’ennesima volta se e come era possibile fare ricerche case insensitive su database Oracle (versione 11.2) ho prima dato la solita risposta, poi però mi è venuto lo scrupolo di ricontrollare se fosse cambiato qualcosa sulla versione che attualmente usiamo maggiormente (11.2.0.3 o 11.2.0.4) e sulla nuova 12.1 che installai qualche mese fa per i primi test sulle novità della versione. Riporto sotto il test completo che ho eseguito rispettivamente su un Oracle 10.2.0.5, un 11.2.0.3 e un 12.1.0.1, prima però anticipo alcune conclusioni: con la 11.2.0.3 le cose sono migliorate rispetto alla 10.2, mentre fra la 11.2 e la 12.1 non noto differenze rilevanti, neanche confrontanto velocemente lo stesso capitolo della documentazione nelle tre versioni:

SQL*Plus: Release 12.1.0.1.0 Production on Fri Aug 22 15:57:31 2014

Copyright (c) 1982, 2013, 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

PL/SQL procedure successfully completed.

Session altered.

CRISTIAN@geotutf8 > create table test_ci_search (id number,string1 varchar2(30),string2 varchar2(30) ,numero number,data date, datastamp timestamp);

Table created.

CRISTIAN@geotutf8 > create sequence stest_ci_search;

Sequence created.

CRISTIAN@geotutf8 > insert into test_ci_search
2  select stest_ci_search.nextval, dbms_random.string('A',30), dbms_random.string('P',30), dbms_random.random,sysdate, systimestamp
3  from dual connect by level <= 100000;

100000 rows created.

CRISTIAN@geotutf8 > insert into test_ci_search select stest_ci_search.nextval, upper(string1), upper(String2), numero, data,datastamp from test_ci_search;

100000 rows created.

CRISTIAN@geotutf8 > insert into test_ci_search select stest_ci_search.nextval, lower(string1), lower(String2), numero, data,datastamp from test_ci_search where id<=100000
;

100000 rows created.

CRISTIAN@geotutf8 > insert into test_ci_search values (stest_ci_search.nextval,'Cristian','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@geotutf8 > insert into test_ci_search values (stest_ci_search.nextval,'CriStian','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@geotutf8 > insert into test_ci_search values (stest_ci_search.nextval,'CRISTIAN','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@geotutf8 > insert into test_ci_search values (stest_ci_search.nextval,'cristian','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@geotutf8 > commit;

Commit complete.

CRISTIAN@geotutf8 > select * from test_ci_search where string1 ='cristian';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300004 cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.832366 PM

CRISTIAN@geotutf8 > ALTER SESSION SET NLS_COMP=LINGUISTIC;

Session altered.

CRISTIAN@geotutf8 > ALTER SESSION SET NLS_SORT=BINARY_CI;

Session altered.

CRISTIAN@geotutf8 > select * from test_ci_search where string1 ='cristian';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300001 Cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.012672 PM

300002 CriStian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.031840 PM

300003 CRISTIAN                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.051397 PM

300004 cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.832366 PM

CRISTIAN@geotutf8 > select * from test_ci_search where string1 like 'cris%';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300001 Cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.012672 PM

300002 CriStian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.031840 PM

300003 CRISTIAN                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.051397 PM

300004 cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.832366 PM

CRISTIAN@geotutf8 > create index test_ci_search_idx on test_ci_search (nlssort(string1,'nls_sort=binary_ci'));

Index created.

CRISTIAN@geotutf8 >  set autotrace on
CRISTIAN@geotutf8 > select * from test_ci_search where string1 like 'cris%';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300001 Cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.012672 PM

300002 CriStian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.031840 PM

300003 CRISTIAN                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.051397 PM

300004 cristian                       Cudizio                                 1 22-08-2014 15:57:54
22-AUG-14 03.57.54.832366 PM

Execution Plan
----------------------------------------------------------
Plan hash value: 18365057

------------------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                |    46 |  3772 |   913   (1)| 00:00:11 |
|*  1 |  TABLE ACCESS FULL| TEST_CI_SEARCH |    46 |  3772 |   913   (1)| 00:00:11 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("STRING1" LIKE 'cris%')

Note
-----
- dynamic sampling used for this statement

&nbsp;


C:\tmp>sqlplus cristian/cristian@//10.110.3.52/salespdb

SQL*Plus: Release 12.1.0.1.0 Production on Fri Aug 22 13:08:07 2014

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

ERROR:
ORA-28002: the password will expire within 7 days

Last Successful login time: Wed Apr 09 2014 15:21:53 +02:00

Connected to:
Oracle Database 12c Release 12.1.0.1.0 - 64bit Production

PL/SQL procedure successfully completed.

Session altered.

CRISTIAN@//10.110.3.52/salespdb > create table test_ci_search (id number,string1 varchar2(30),string2 varchar2(30) ,numero number,data date, datastamp timestamp);

Table created.

CRISTIAN@//10.110.3.52/salespdb > create sequence stest_ci_search;

Sequence created.

CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search
2  select stest_ci_search.nextval, dbms_random.string('A',30), dbms_random.string('P',30), dbms_random.random,sysdate, systimestamp
3  from dual connect by level <= 100000;

100000 rows created.

CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search select stest_ci_search.nextval, upper(string1), upper(String2), numero, data,datastamp from test_ci_search;

100000 rows created.

CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search select stest_ci_search.nextval, lower(string1), lower(String2), numero, data,datastamp from test_ci_search wh
ere id<=100000;

100000 rows created.

CRISTIAN@//10.110.3.52/salespdb >
CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search values (stest_ci_search.nextval,'Cristian','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search values (stest_ci_search.nextval,'CriStian','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search values (stest_ci_search.nextval,'CRISTIAN','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@//10.110.3.52/salespdb > insert into test_ci_search values (stest_ci_search.nextval,'cristian','Cudizio',1,sysdate,systimestamp);

1 row created.

CRISTIAN@//10.110.3.52/salespdb >
CRISTIAN@//10.110.3.52/salespdb > commit;

Commit complete.

CRISTIAN@//10.110.3.52/salespdb > select * from test_ci_search where string1 ='cristian';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300004 cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.484698 PM

CRISTIAN@//10.110.3.52/salespdb > ALTER SESSION SET NLS_COMP=LINGUISTIC;

Session altered.

CRISTIAN@//10.110.3.52/salespdb > ALTER SESSION SET NLS_SORT=BINARY_CI;

Session altered.

CRISTIAN@//10.110.3.52/salespdb > select * from test_ci_search where string1 ='cristian';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300001 Cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.457087 PM

300002 CriStian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.466520 PM

300003 CRISTIAN                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.475596 PM

300004 cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.484698 PM

CRISTIAN@//10.110.3.52/salespdb > select * from test_ci_search where string1 like 'cris%';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300001 Cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.457087 PM

300002 CriStian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.466520 PM

300003 CRISTIAN                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.475596 PM

300004 cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.484698 PM

CRISTIAN@//10.110.3.52/salespdb > create index test_ci_search_idx on test_ci_search (nlssort(string1,'nls_sort=binary_ci'));

Index created.

CRISTIAN@//10.110.3.52/salespdb > set autotrace on
ERROR:
ORA-28002: the password will expire within 7 days

SP2-0619: Error while connecting
SP2-0611: Error enabling STATISTICS report
CRISTIAN@//10.110.3.52/salespdb > select * from test_ci_search where string1 like 'cris%';

ID STRING1                        STRING2                            NUMERO DATA
---------- ------------------------------ ------------------------------ ---------- -------------------
DATASTAMP
---------------------------------------------------------------------------
300001 Cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.457087 PM

300002 CriStian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.466520 PM

300003 CRISTIAN                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.475596 PM

300004 cristian                       Cudizio                                 1 22-08-2014 13:11:06
22-AUG-14 01.11.06.484698 PM

Execution Plan
----------------------------------------------------------
Plan hash value: 1977262958

----------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name               | Rows  | Bytes | Cost (%CPU)| Time  |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                    |   780 |   159K|  1125   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TEST_CI_SEARCH     |   780 |   159K|  1125   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | TEST_CI_SEARCH_IDX |  1404 |       |    11   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access(NLSSORT("STRING1",'nls_sort=''BINARY_CI''')>=HEXTORAW('6372697300') AND
NLSSORT("STRING1",'nls_sort=''BINARY_CI''')<HEXTORAW('6372697400'))

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

In sintesi, fino a Oracle 10.2.0.5 era possibile abilitare ricerche su stringhe in modalità case insensitive, il problema era però che dall’uso dell’indice linguistico erano escluso l’operatore LIKE, dalla versione 11.2 in poi invece anche con l’operatore LIKE viene usato l’indice. Ho riportato solo i test per 10.2.0.5 e 12.1.0.1, per 11.2.0.3 il risultato è uguale a quello di 12.1.0.1

Novità sulla gestione dello spazio in Oracle 11gR2

venerdì 30 maggio 2014 alle 30:22 | Pubblicato su 11g | 1 commento

Sono un po’ indietro,  questo spiega un post su una novità introdotta con Oracle 11gR2 (in realtà parte con 11.2.0.2) a diversi mesi dall’uscita di oracle 12c. Sto cercando di non rimanere indietro e di non perdermi informazioni, quindi sto ripassando il manuale “Oracle® Database New Features Guide” versione 11gR2, quando avrò finito con quello potrò permettermi di passare all’equivalente manuale versione 12c R1. La maggior parte delle nuove funzionalità e caratteristiche introdotte da Oracle non mi interessa, cerco di contentrarmi su quelle che posso sfruttare utilmente, senza sprecare risorse a studiare a tappeto tutto. Una su cui secondo me vale la pena soffermarsi, o meglio due, sono la gestione dello spazio, tramite l’uso del comando “TRUNCATE” e tramite l’uso del package DBMS_SPACE_ADMIN.

Il comando TRUNCATE è stato esteso per poter richiedere o  meno il rilascio dello spazio allocato dalla tabella. Il comando usato come nelle versioni precedenti, ad esempio:


TRUNCATE TABLE test_truncate;

Si comporta come nelle versioni precedenti di Oracle (lasciando allocati gli extent eventualmente indicati con il parametro MINEXTENT). Quanto sopra è equivalente, con la nuova estensione a:


TRUNCATE TABLE test_truncate DROP STORAGE;

Vi sono poi due possibilità nuove, la prima è lasciare lo spazio allocato per la tabella allocato, in tal caso il comando usa l’opzione “REUSE STORAGE”:


TRUNCATE TABLE test_truncate REUSE STORAGE;

All’estremo opposto vi è la possibilità di rilasciare tutto, ma proprio tutto lo spazio allocato dalla tabella eliminando il segmento, in questo caso l’opzione è “DROP ALL STORAGE”:


TRUNCATE TABLE test_truncate DROP ALL STORAGE;

Cerco di riportare un po’ di esempi per fare capire meglio.


SVILUPPO40@SVIL112_METHONE > create table test_truncate(a number, b varchar2(4000));

Table created.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name = 'TEST_TRUNCATE' ;

no rows selected

SVILUPPO40@SVIL112_METHONE > begin
2  for i in 1..10000 loop
3  insert into test_truncate values (1,rpad('testxx',4000,'z'));
4  end loop;
5  end;
6  /

PL/SQL procedure successfully completed.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

SEGMENT_NAME                                                                              MB
--------------------------------------------------------------------------------- ----------
TEST_TRUNCATE                                                                             80

SVILUPPO40@SVIL112_METHONE > TRUNCATE TABLE test_truncate REUSE STORAGE;

Table truncated.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

SEGMENT_NAME                                                                              MB
--------------------------------------------------------------------------------- ----------
TEST_TRUNCATE                                                                             80

SVILUPPO40@SVIL112_METHONE > TRUNCATE TABLE test_truncate ;

Table truncated.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

SEGMENT_NAME                                                                              MB
--------------------------------------------------------------------------------- ----------
TEST_TRUNCATE                                                                          .0625

SVILUPPO40@SVIL112_METHONE > TRUNCATE TABLE test_truncate REUSE STORAGE;

Table truncated.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

SEGMENT_NAME                                                                              MB
--------------------------------------------------------------------------------- ----------
TEST_TRUNCATE                                                                          .0625

SVILUPPO40@SVIL112_METHONE > TRUNCATE TABLE test_truncate DROP ALL STORAGE;

Table truncated.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

no rows selected

SVILUPPO40@SVIL112_METHONE > DROP TABLE TEST_TRUNCATE PURGE;

Table dropped.


SVILUPPO40@SVIL112_METHONE > create table test_truncate(a number, b varchar2(4000)) STORAGE (MINEXTENTS 100);

Table created.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

no rows selected

SVILUPPO40@SVIL112_METHONE > INSERT INTO test_truncate values (1,'a');

1 row created.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

SEGMENT_NAME                                                                              MB
--------------------------------------------------------------------------------- ----------
TEST_TRUNCATE                                                                            104

SVILUPPO40@SVIL112_METHONE > TRUNCATE TABLE test_truncate;

Table truncated.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

SEGMENT_NAME                                                                              MB
--------------------------------------------------------------------------------- ----------
TEST_TRUNCATE                                                                            104

SVILUPPO40@SVIL112_METHONE > TRUNCATE TABLE test_truncate DROP ALL STORAGE;

Table truncated.

SVILUPPO40@SVIL112_METHONE > select SEGMENT_name,BYTES/1024/1024 MB from user_segments where segment_name like '%TEST_TRUNCATE' ;

no rows selected

SVILUPPO40@SVIL112_METHONE >

Parallelamente al package DBMS_SPACE_MANAGEMENT sono state aggiunte due procedure:

  1. DROP_EMPTY_SEGMENTS
  2. MATERIALIZE_DEFERRED_SEGMENTS

Il primo può essere utile in caso di database migrati, in cui ci sono magari un sacco di tabelle vuote per cui, provenendo da versioni Oracle precedenti alla 11.2 dove non esisteva la “deferred segment creation”, vengono comunque creati i segmenti. Va detto che nei miei casi si tratta comunque di briciole di spazio per cui non so quanto valga la pena rompersi, ma se uno vuole raschiare il fondo così può farlo 🙂 Il package DBMS_SPACE_ADMIN anche se non scritto in modo chiarissimo sul manuale, mi risulta utilizzabile solo da utente SYS, invocando la procedure DROP_EMPTY_SEGMENTS specificando solo il primo parametro (lo schema) viene spazolato tutto lo schema e per le tabelle vuote vengono eliminati i segmenti, altrimenti è possibile specificare le tabelle per cui si vuole agire.

L’utilità della procedura MATERIALIZE_DEFERRED_SEGMENTS mi viene ancora più difficile da immaginare, comunqu, per completezza fa esattamente il contrario della precedente, crea il segmento di partenza per tutte le tabelle.

Pagina successiva »

Crea un sito o un blog gratuitamente presso WordPress.com.
Entries e commenti feeds.