Oracle
 sql >> Base de données >  >> RDS >> Oracle

Zéro final

Un développeur m'a récemment posé une question intéressante. Il travaillait sur un problème où des valeurs numériques étaient stockées dans une table, mais lorsqu'il interrogeait cette table dans PL/SQL Developer, elle affichait des zéros à la fin après le dernier chiffre. Il se demandait si cela contribuait au problème qu'il essayait de déboguer. Le développeur avait besoin de savoir si Oracle stockait ces zéros à droite.

Ma réponse a été qu'Oracle ne stocke pas les zéros à la fin. Oracle ne stocke que l'exposant et la mantisse du nombre. Oracle ne remplit pas à droite la valeur numérique avec des zéros. Le développeur savait maintenant que son problème n'était pas lié aux données de la base de données, mais plutôt à quelque chose que faisait sa plate-forme de développement.

Mais ma déclaration était-elle vraie ? Plusieurs fois, j'ai fait une déclaration sur le fonctionnement d'Oracle en interne, mais j'ai ensuite dû revenir en arrière et valider ma déclaration ou prouver qu'elle était fausse, ce qui conduit inévitablement à la bonne déclaration.

Pour tester ma déclaration, j'ai créé un tableau simple et y ai inséré des données.

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

Dans SQL*Plus, nous ne voyons aucun zéro à la fin même si je les ai explicitement ajoutés. Les valeurs 25 et 25.0 ainsi que 25.2 et 25.20 se ressemblent toutes. Mais c'est peut-être ainsi que SQL*Plus affiche les valeurs. Vidons donc le bloc de données pour voir exactement comment Oracle stocke ces valeurs.

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.

J'ai dû déterminer le numéro de fichier et de bloc pour mon segment que j'ai créé. J'ai ensuite émis la commande pour vider le contenu des blocs de données dans un fichier de trace. Lorsque vous regardez dans le fichier de trace, recherchez le mot-clé « block_row_dump » et vous pouvez voir le contenu de ces lignes dans le vidage ci-dessous :

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

Nous pouvons voir à partir du vidage de bloc que la première valeur est longue de 2 octets et se compose des caractères hexadécimaux "C1 1A". La deuxième ligne a exactement les mêmes valeurs ! Ceci est important car il vérifie mon affirmation initiale selon laquelle Oracle ne stocke aucun zéro supplémentaire pour la deuxième ligne du tableau. S'il y avait un zéro supplémentaire, la longueur ne serait pas de 2 octets. Pour la troisième et la quatrième ligne, nous pouvons voir que les valeurs hexadécimales sont identiques, "C1 1A 15".

Mais assurons-nous que ces valeurs hexadécimales correspondent à nos données. Pour ce faire, nous allons utiliser la procédure 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.

Ainsi, les valeurs hexadécimales "C1 1A" sont la représentation interne (brute) de '25' et "C1 1A 15" est 25,2 comme nous l'aurions prévu.

La morale de cette histoire est que parfois, lorsque vous pensez savoir comment Oracle fonctionne en interne, vous devrez peut-être encore concevoir un cas de test pour valider vos déclarations.