lundi 16 mai 2011

Nouveauté 11g R2: Segment Deferred Creation

Si vous travaillez avec des bases 11g R2 il est possible que vous tombiez sur l’erreur suivante lors d’un export:
EXP-00003: no storage definition found for segment(0, 0)
. . exporting table                  T1

Le descriptif de l’erreur est plutôt clair : il indique qu’il n’existe pas de segment associé à la table T1.
En effet, si on requête la vue USER_SEGMENTS pour récupérer le segment associé à la table T1 on constate que ce segment n’existe pas :
SQL> select count(*) from user_segments where segment_name='T1';
 
  COUNT(*)
----------
         0

SQL> select count(*) from user_tables where table_name='T1';
 
  COUNT(*)
----------
         1

Ceci est en fait dû à une nouvelle fonctionnalité de la 11g R2 appelée « Segment Deferred Creation ». En effet, jusqu’à la 11g R1 inclus lorsque qu’on créait une table vide, Oracle allouait automatiquement de l’espace (un extent). On avait donc un segment associé à cette table. Avec la 11g R2, Oracle par défaut ne crée plus de segment pour une table tant qu’on n’a pas inséré de lignes dedans ou qu’on n’ait pas demandé explicitement à Oracle de la faire via la commande ALLOCATE EXTENT :
SQL> alter table t1 allocate extent;
 
Table altered
 
SQL> select count(*) from user_segments where segment_name='T1';
 
  COUNT(*)
----------
         1

Ce comportement par défaut d’Oracle en 11g R2 peut-être changé en touchant au paramètre d’instance DEFERRED_SEGMENT_CREATION. Par défaut celui-ci est à TRUE ce qui veut dire que la création du segment lors du CREATE TABLE n’est pas immédiate. Ce paramètre peut être modifiable au niveau de la session :
SQL> drop table t1 purge;
 
Table dropped
 
SQL> create table t1 (c1 NUMBER, C2 varchar2(50));
 
Table created
 
SQL> select count(*) from user_segments where segment_name='T1';
 
  COUNT(*)
----------
         0
 
SQL> drop table t1 purge;
 
Table dropped
 
SQL> alter session set deferred_segment_creation=false;
 
Session altered
 
SQL> create table t1 (c1 NUMBER, C2 varchar2(50));
 
Table created
 
SQL> select count(*) from user_segments where segment_name='T1';
 
  COUNT(*)
----------
         1

Dans cet exemple on voit que lorsque le paramètre DEFERRED_SEGMENT_CREATION est à TRUE le segment n’est pas crée automatiquement lors de la commande DDL. Par contre lorsque le paramètre est à FALSE on retrouve le comportement d’Oracle des versions précédentes c’est à dire que le segment est crée immédiatement.

Il est également possible de spécifier cette option directement au niveau de la commande DDL via la clause SEGMENT CREATION.
Par défaut la clause est SEGMENT CREATION DEFERRED mais on peut spécifier à la place SEGMENT CREATION IMMEDIATE :

SQL> drop table t1 purge;
 
Table dropped
 
SQL> alter session set deferred_segment_creation=TRUE;
 
Session altered
 
SQL> create table t1 (c1 NUMBER, C2 varchar2(50)) SEGMENT CREATION DEFERRED;
 
Table created
 
SQL> select count(*) from user_segments where segment_name='T1';
 
  COUNT(*)
----------
         0
 
SQL> drop table t1 purge;
 
Table dropped
 
SQL> create table t1 (c1 NUMBER, C2 varchar2(50)) SEGMENT CREATION IMMEDIATE;
 
Table created
 
SQL> select count(*) from user_segments where segment_name='T1';
 
  COUNT(*)
----------
         1

Si vous effectuez ces tests sur votre base et que vous obtenez l’erreur « ORA-14223: Deferred segment creation is not supported for this table », c’est surement que vous utilisez le user SYS ou SYSTEM. Or cette fonctionnalité ne s'applique pas sur ces schémas là.

Dans la vue USER_TABLES existe en 11g R2 une nouvelle colonne SEGMENT_CREATED qui indique si oui ou non le segment associé à la table est crée :
SQL> drop table t1 purge;
 
Table dropped

SQL> create table t1 (c1 NUMBER, C2 varchar2(50)) ;

Table created.

SQL> select count(*) from user_segments where segment_name='T1';

  COUNT(*)
----------
         0

SQL> select SEGMENT_CREATED  from user_tables where table_name='T1';

SEG
---
NO

SQL> alter table T1 allocate extent;

Table altered.

SQL> select SEGMENT_CREATED  from user_tables where table_name='T1';

SEG
---
YES


Sachez aussi qu’en 11.2.0.1 la fonctionnalite Segment Deferred Creation ne peut pas être appliqué aux tables partitionnées, mais qu’en 11.2.0.2 c’est désormais possible.

Si un jour en analysant les statistiques d’exécution d’un plan vous constatez que le nombre de lectures logiques pour un Full Table Scan est de 0 c’est surement que la table n’a pas de segment associé :
SQL> create table t1 (c1 NUMBER, C2 varchar2(50)) ;

Table created.

SQL> select * from t1;

no rows selected

SQL> set autotrace traceonly statistics
SQL> select * from t1;

no rows selected


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          0  consistent gets
          0  physical reads
          0  redo size
        338  bytes sent via SQL*Net to client
        405  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

SQL> set autot off

Aucune lecture logique ni lecture physique n’a été effectué pour cette requête.
Maintenant si j’alloue de l’espace à la table T1 des lectures logiques seront effectuées (même si la table ne contient pas de lignes) :

SQL> alter table t1 allocate extent;

Table altered.

SQL> select * from t1;

no rows selected

SQL> set autotrace traceonly statistics
SQL> select * from t1;

no rows selected


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        338  bytes sent via SQL*Net to client
        405  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

SQL> set autot off

Pour ceux qui auront remarqué que j’ai exécuté 2 fois la requête pour les 2 cas, c’est en fait juste pour ne prendre en compte que les I/O liés à l’exécution de la requête elle-même et non pas les éventuels I/O effectués par Oracle lors du parsing de la requête.

7 commentaires:

  1. un autre effet secondaire du Deferred Segment est que l'on n'a pas besoin de quota pour créer une table vide...

    RépondreSupprimer
  2. Effectivement un user qui n'a pas les droits de créer un segment sur un tablespace donné peut créer une table en mode SEGMENT CREATION DEFERRED. Par contre le USER rencontrera une erreur au moment où il voudra y insérer des lignes car c'est à ce moment que le segment est crée.

    RépondreSupprimer
  3. Bonsoir ,
    meme en changeant la valeur de parameter SEGMENT CREATION DEFERRED est a false , au niveau v$option ça reste activé
    PARAMETER
    --------------------------
    VALUE
    --------------------------
    Deferred Segment Creation
    TRUE

    et ça plante toujours l'export en renvoyant le meme code erreur
    EXP-00003: no storage definition found for segment(0, 0)

    Une idée svp ?
    Merci

    RépondreSupprimer
  4. V$OPTION t'indique juste si une option Oracle est installée ou pas.
    Pour vérifier si un paramètre est désactivé il faut regarder dans V$PARAMETER.

    Concernant ton pb d'export, il plante car il n'y a pas de segment associé à ta table. Il faut donc, avant de faire ton export, allouer un extent à ta table avec par exemple la commande ALLOCATE EXTENT

    RépondreSupprimer
  5. thanks for this !!! it helped me out a lot !

    RépondreSupprimer
  6. Bonjour Ahmed,
    Je suis développeur en automatisme et informatique industrielle, donc j'utilise frequemment des bases ORACLE pour stocker les données de production.
    j'utilise l'outil ORACLE SQL DEVELOPER Version 4.0.3.16 et SQL DATA MODELER(que je trouve très bien) pour créer, modifier des tables sur une base ORACLE existante en version 8 et 9.
    Effectivement (comme vous l'avez fait remarquer) sur ma plateforme de développement il génère un script avec la clause SEGMENT CREATION IMMEDIATE, que refuse la base 8 et 9.
    Question : comment paramétrer SQL DEVELOPER pour qu'il génére des scripts conformes au format ORACLE 8 et 9, pour ensuite les importerr dans la base ORACLE.

    RépondreSupprimer