sql >> Databasteknik >  >> RDS >> Oracle

Efterstående noll

Jag fick en utvecklare att ställa en intressant fråga till mig nyligen. Han arbetade med ett problem där numeriska värden lagrades i en tabell men när han frågade den tabellen i PL/SQL Developer, visade den efterföljande nollor efter den sista siffran. Han undrade om detta bidrog till problemet han försökte felsöka. Utvecklaren behövde veta om Oracle lagrade de efterföljande nollorna.

Mitt svar var att Oracle inte lagrar efterföljande nollor. Oracle lagrar bara exponenten och mantissan för talet. Oracle lägger inte nollor till höger på det numeriska värdet. Utvecklaren visste nu att hans problem inte var med data i databasen utan snarare något som hans utvecklingsplattform gjorde.

Men var mitt påstående sant? Många gånger har jag gjort ett uttalande om hur Oracle fungerar internt men sedan varit tvungen att gå tillbaka och validera mitt uttalande eller bevisa att det var falskt vilket oundvikligen leder till rätt påstående.

För att testa mitt uttalande skapade jag en enkel tabell och infogade data i den.

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

I SQL*Plus ser vi inga efterföljande nollor även om jag uttryckligen lagt till dem. Värdena 25 och 25.0 samt 25.2 och 25.20 ser alla likadana ut. Men kanske är det bara så här SQL*Plus visar värdena. Så låt oss dumpa datablocket för att se exakt hur Oracle lagrar dessa värden.

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.

Jag var tvungen att bestämma filen och blocknumret för mitt segment jag skapade. Jag utfärdade sedan kommandot att dumpa innehållet i datablocken till en spårningsfil. När du tittar i spårningsfilen, sök efter nyckelordet "block_row_dump" och du kan se innehållet i dessa rader i dump nedan:

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

Vi kan se från blockdumpen att det första värdet är 2 byte långt och består av hextecken "C1 1A". Den andra raden har exakt samma värden! Detta är viktigt eftersom det verifierar mitt ursprungliga påstående att Oracle inte lagrar några extra nollor för den andra raden i tabellen. Om det fanns en extra nolla skulle längden inte vara 2 byte. För den tredje och fjärde raden kan vi se att hex-värdena är identiska, "C1 1A 15".

Men låt oss vara säkra på att dessa hexadecimala värden motsvarar våra data. För att göra det använder vi proceduren 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.

Så hex-värdena "C1 1A" är den interna (rå) representationen av '25' och "C1 1A 15" är 25,2 som vi hade förväntat oss.

Moralen i den här historien är att ibland när du tror att du vet hur Oracle fungerar internt, kanske du fortfarande måste utarbeta ett testfall för att validera dina påståenden.


  1. SQLite CASE

  2. Ändra en CHECK-begränsning i SQL Server med T-SQL

  3. En översikt över VACUUM-bearbetning i PostgreSQL

  4. Millisekunder i min DateTime ändras när den lagras i SQL Server