Oracle
 sql >> Database >  >> RDS >> Oracle

Zero finale

Di recente uno sviluppatore mi ha fatto una domanda interessante. Stava lavorando su un problema in cui i valori numerici erano memorizzati in una tabella, ma quando ha interrogato quella tabella in PL/SQL Developer, mostrava zeri finali dopo l'ultima cifra. Si chiese se questo stesse contribuendo al problema che stava cercando di eseguire il debug. Lo sviluppatore doveva sapere se Oracle stava archiviando quegli zeri finali.

La mia risposta è stata che Oracle non memorizza gli zeri finali. Oracle memorizza solo l'esponente e la mantissa del numero. Oracle non esegue il tastierino destro del valore numerico con zeri. Lo sviluppatore ora sapeva che il suo problema non era con i dati nel database, ma piuttosto con qualcosa che stava facendo la sua piattaforma di sviluppo.

Ma la mia affermazione era vera? Molte volte ho fatto una dichiarazione su come Oracle funziona internamente, ma poi ho dovuto tornare indietro e convalidare la mia dichiarazione o dimostrare che era falsa, il che porta inevitabilmente all'affermazione corretta.

Per testare la mia affermazione, ho creato una semplice tabella e vi ho inserito dei dati.

SQL> create table test_tab (val number(38,5));
Table created.
SQL> insert into test_tab values (25);
1 row created.
SQL> insert into test_tab values (25.0);
1 row created.
SQL> insert into test_tab values (25.2);
1 row created.
SQL> insert into test_tab values (25.20);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test_tab;
VAL
----------
        25
        25
      25.2
      25.2

In SQL*Plus, non vediamo zeri finali anche se li ho aggiunti esplicitamente. I valori 25 e 25.0 così come 25.2 e 25.20 sembrano tutti uguali. Ma forse questo è proprio il modo in cui SQL*Plus sta visualizzando i valori. Quindi eseguiamo il dump del blocco di dati per vedere come esattamente Oracle sta archiviando questi valori.

SQL> select file_id,block_id,blocks
2  from dba_extents where segment_name='TEST_TAB';
FILE_ID   BLOCK_ID     BLOCKS
---------- ---------- ----------
6        128          8
SQL> alter system dump datafile 6 block min 128 block max 135;
System altered.

Ho dovuto determinare il file e il numero di blocco per il mio segmento che ho creato. Ho quindi emesso il comando per eseguire il dump del contenuto dei blocchi di dati in un file di traccia. Quando guardi nel file di traccia, cerca la parola chiave "block_row_dump" e puoi vedere il contenuto di queste righe nel dump di seguito:

block_row_dump:
tab 0, row 0, @0x1f92
tl: 6 fb: --H-FL-- lb: 0x1  cc: 1
col  0: [ 2]  c1 1a
tab 0, row 1, @0x1f8c
tl: 6 fb: --H-FL-- lb: 0x1  cc: 1
col  0: [ 2]  c1 1a
tab 0, row 2, @0x1f85
tl: 7 fb: --H-FL-- lb: 0x1  cc: 1
col  0: [ 3]  c1 1a 15
tab 0, row 3, @0x1f7e
tl: 7 fb: --H-FL-- lb: 0x1  cc: 1
col  0: [ 3]  c1 1a 15
end_of_block_dump

Dal block dump il primo valore è lungo 2 byte ed è composto dai caratteri esadecimali “C1 1A”. La seconda riga ha gli stessi valori esatti! Questo è importante perché verifica la mia affermazione iniziale secondo cui Oracle non sta memorizzando zeri aggiuntivi per la seconda riga della tabella. Se ci fosse uno zero in più, la lunghezza non sarebbe 2 byte. Per la terza e la quarta riga, possiamo vedere che i valori esadecimali sono identici, "C1 1A 15".

Ma assicuriamoci che questi valori esadecimali corrispondano ai nostri dati. Per farlo, utilizzeremo la procedura DBMS_STATS.CONVERT_RAW_VALUE.

SQL> set serveroutput on

SQL> declare

  2  n number;

  3  begin

  4  dbms_stats.convert_raw_value('C11A',n);

  5  dbms_output.put_line(n);

  6  end;

  7  /

25

 

PL/SQL procedure successfully completed.

 

SQL> declare

  2  n number;

  3  begin

  4  dbms_stats.convert_raw_value('C11A15',n);

  5  dbms_output.put_line(n);

  6  end;

  7  /

25.2

 

PL/SQL procedure successfully completed.

Quindi i valori esadecimali "C1 1A" sono la rappresentazione interna (grezza) di "25" e "C1 1A 15" è 25,2 come ci saremmo aspettati.

La morale di questa storia è che a volte quando pensi di sapere come funziona Oracle internamente, potresti comunque dover escogitare un banco di prova per convalidare le tue affermazioni.