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.

Nome del file o estensione troppo lunga in Windows

mercoledì 28 maggio 2014 alle 28:05 | Pubblicato su Diario | Lascia un commento

Evidentemente non potrò mai essere un buon programmatore, perché non so usare gli “IDE”; ieri ho provato a giocchicchiare un po’ con Netbeans 7.3 e cercando di aggiungere delle librerie al progetto ho fatto evidententemente qualcosa di sbagliato, tant’è che ho dovuto uccidere il programma perché non ne usciva più. Stamattina ho deciso di riprovarci ed ho cominciato con il fare pulizia, trovandomi però con un bizzarro problema: all’interno della directory dove dovevano stare le librerie Netbeans aveva creato ricorsivamente decine, forse centinaia di directory innestate con lo stesso nome, una cosa tipo C:\progetto\lib\lib\lib\lib\lib\…

Bisogna sapere che quando il percorso assoluto di un file in windows supera i 260 caratteri windows non è più in grado di gestirlo e cercando di rimuoverlo si ottiene un errore tipo quello che da il titolo a questo post, sia provando da Explorer che da linea di comando. C’è da chiedersi perché windows ne permetta la creazione ma poi non sia capace di gestirli… Lo stesso problema può capitare con un nome di file troppo lungo, in questo caso però forse si riesce a fare la rinomina, non ne sono sicuro.

Ho iniziato allora dopo tentativi da linea di comando svariati a cercare su internet ma le soluzioni trovate facendo una ricerca per il testo dell’errore in italiano non funzionavano per la mia situazione, quindi ho provato a fare la ricerca traducendo (alla meno peggio) in inglese il testo del messaggio, quindi con i termini “filename or extension too long” alla fine sono arrivato a questa pagina (parrebbe un forum ufficiale microsoft, in precedenza ero capitato sullo stesso sito ma su una discussione in italiano dove non si fornivano soluzioni..). Qui si propone come soluzione l’uso di Cygwin e del comando “rm”, io ho provato con il comando rm che trovo gia installato su Windows 7, senza aver mai installato Cygwin ma non funziona, stesso errore, prima di provare allora a installare Cygwin ho continuato a scorrere la discussione fino alla soluzione proposta da “Augustin Botana” (avrei volentieri messo il link alla singola risposta, ma evidentemente in MS non conoscono queste feature così avanzate …) il quale spiega di avere avuto lo stesso problema con netbeans, mi permetto di citare il suo intervento:

Hi.

I had the same problem but with netbeans which built recursive folders with the root given name. I used the name “mermelada” under my c:\temp\ folder.

I had thousands (at least) of c:\temp\mermelada\mermelada…. And so and not able to delete because the windows “name too long” message.

I used the inspiration of another user of this issue and made a recupera2.bat with the following content

ren c:\temp\mermelada\mermelada\mermelada x

move c:\temp\mermelada\mermelada\x c:\temp\mermelada

rd c:\temp\mermelada\mermelada

ren c:\temp\mermelada\x mermelada

recupera2.bat

In a DOS window, I ran c:\recupera2.bat, leaved alone for 2 minutes and voila!… just a empty “mermalada” folder  ready to be destroyed.

Good luck!

 

Ecco, la soluzione è geniale, uno script ricorsivo, l’ho adattato al mio caso ed ha funzionato benissimo

Database server con più “Time Zone”

lunedì 19 maggio 2014 alle 19:52 | Pubblicato su Diario | Lascia un commento
Tag: ,

Recentemente mi è stata commissionata un’indagine su come è possibile gestire più “Time Zone” su un database Oracle o più database Oracle sulla stessa macchina, siccome il risultato delle mie indagini mi è parso interessante e ho voglia di organizzare tale risultato al fine di trovare più rapidamente le informazioni la prossima volta che mi serviranno (se mai capiterà) ho deciso di scrivere questo post riepilogativo.

Quando mi è stato sottoposto il problema ho deciso di partire subito dal supporto Oracle, partendo dalla presunzione che per una singola istanza Oracle non fosse possibile “vedere” più time zone contemporaneamente. Quindi ho iniziato con una ricerca per i termini “multiple instances different timezones” ed ho cominciato con il primo documento rilevante che è:

How to use multiple timezones with one Oracle RAC database (Doc ID 1531653.1)

Nel mio caso non si usa RAC, quindi sono passato subito al primo documento indicato dopo poche righe:

How To setup TNS listener to Show More Than one Timezone (Doc ID 399448.1)

Questo è stato il primo documento che mi ha fatto pensare: “questo è interessante e me lo devo segnare”. In esso viene spiegato come, ad esclusione di ambienti Windows, dove a causa dell’architettura monoprocesso/multithread la soluzione non funziona, è possibile avviare per una singola istanza Oracle più listener, ciascuno dei quali fa vedere ai client collegati il database su una specifica “time zone” specificata sotto forma di variabile d’ambiente TZ nella configurazione del listener sul file listener.ora. La variabile TZ viene passata i processi server che vengono creati su richiesta del listener per soddisfare la richiesta di connessione. Questo funziona solo se non si usano “Shared Server” (perché in quel caso non c’è la creazione del nuovo processo, do’ per scontata la conoscenza dei meccanismi Oracle per la gestione delle richieste di connessione in caso di “dedicated server” e “shared server”). Altra condizione indicata nel documento è che la connessione avvenga tramite SID, su questo non ho indagato in realtà, ma non essendo un problema l’ho preso per buono.

Per fare qualche controllo mi sono ripassato e riporto altri interessanti documenti:

Dates & Calendars – Frequently Asked Questions (Doc ID 227334.1)

Timestamps & time zones – Frequently Asked Questions (Doc ID 340512.1)

Database Timezone Configuration (Doc ID 745854.1)

Ci sono cose che ho gia riassunto in un mio vecchio post e altro. Alla fine pare che la Time Zone del server influisca solo sulle funzioni SYSDATE e SYSTIMESTAMP, nel senso che l’ora del server verrà presentata al client nella time zone impostata; per il resto al client che si collega al database cambia poco (direi nulla, ma metto in conto possa essermi sfuggito qualcosa).

Pagina successiva »

Blog su WordPress.com.
Entries e commenti feeds.