Overblog
Suivre ce blog Administration + Créer mon blog
11 novembre 2008 2 11 /11 /novembre /2008 19:51
Bonsoir

Regardons d'un peu plus près ces histoires de partitions.
Pour cela prenons un exemple simple et insignifiant.



CREATE TABLE t_part (i number,j number)
PARTITION BY RANGE (i) SUBPARTITION BY HASH (j) SUBPARTITIONS 4
(
   PARTITION P1 VALUES LESS THAN (2),
   PARTITION P2 VALUES LESS THAN (3),
   PARTITION P3 VALUES LESS THAN (4)
);



Cas 1:

Nous voila donc avec une table disposant de partitions et sous-partition.
Inserons donc quelques lignes...



INSERT INTO t_part VALUES (1,2);
INSERT INTO t_part VALUES (3,9);
INSERT INTO t_part VALUES (8,2);




Pour les deux premières insertions, aucun soucis, en revanche pour la troisième, ...

ORA-14400 : la clé de partition insérée ne correspond à aucune partition

Voila qui est dit ! j'ai une table et je ne peux pas inserer ce que je veux dedans. En tant qu'administrateur, je dois prévoir la création des partitions au départ. Bien évidemment peut ajouter des partitions par la suite.
On aurait pu palier à ce problème en créeant la table d'une autre façon:



DROP TABLE t_part;
CREATE TABLE t_part (i number,j number)
PARTITION BY RANGE (i) SUBPARTITION BY HASH (j) SUBPARTITIONS 4
(
   PARTITION P1 VALUES LESS THAN (2),
   PARTITION P2 VALUES LESS THAN (3),
   PARTITION P3 VALUES LESS THAN (4),
   PARTITION P_others VALUES LESS THAN (maxvalue)
);



La valeur maxvalue implique qu'il n'y a plus de valeur maximum et que toutes les lignes n'etant pas déstinées à etre dasn P1, P2 ou P3 seront accueillies par P_others.
Si vous rejouez la sequence d'insertion, il n'y aura plus de soucis.
En revanche vous risquez d'avoir des données dans une partition f"ourre tout", qu'il faudra un jour déplacer.
Il n'y a pas de solution magique, c'est le role du DBA de prévoir et créer les partitions nécessaires lorsque cela est utile. Je pense notemment aux tables partitionnées sur des champs date.
Si votre table est partitionnée par mois, vous allez créer les partitions pour l'année 2008 et courrant décembre 2008 vous ajouterez les partitions pour 2009.


Cas 2:

Encore envie de jouer, alors un petit update sur la clé de partition.


UPDATE t_part SET i=1 WHERE i=8;


ORA-14402 : LAa mise à jour de la colonne de clé de partition modifierait la partition.

Décidement, c'est qu'il faudrait presque réfléchir !
Faire un update sur la clé de partition revient à faire un delete puis un insert.
Pour autoriser les update sur la clé de partition, il faut au préalable effectuer la commande suivante.



ALTER TABLE t_part ENABLE ROW MOVEMENT;


Et maintenant vous pouvez faire tous les update que vous voulez. En même temps si vous en faites beaucoup sur la clé de partition c'est peut être que vous avez mal choisi votre clé de partition.

Cas 3 :

Comme vous le savez pour qu'ORACLE puisse choisir le meilleur plan d'execution possible, il faut que les stast soient à jour.
Allons y !


exec DBMS_STATS.GATHER_TABLE_STATS(user,'t_part',CASCADE=>TRUE);

SELECT Table_Name,Last_Analyzed FROM User_Tables WHERE Table_Name='T_PART';
SELECT Partition_Name,Last_Analyzed FROM User_Tab_Partitions WHERE Table_Name='T_PART';
SELECT Subpartition_Name,Last_Analyzed FROM User_Tab_Subpartitions WHERE Table_Name='T_PART';



Magique ! dans les deux premiers cas on constate que la colonne Last_Analysed est bien renseignée alors que pour les sous partitions que dalle ! Ce qui en clair signifie qu'il n'y a pas de statistiques sur mes sous partitions, ce qui à un moment donnée peut poser problème.

Bug oracle ou mauvaise utilisation du package DBMS_STATS
Pas de suspens inutile
Il existe un paramètre GRANULARITY pour le package DBMS_STATS qui a pour valeur par défaut AUTO. Ce qui entraine que les statistiques ne sont pas collectées au niveau sous-partitions.

Il faut passer la valeur ALL dans l'appel de le procédure.



exec DBMS_STATS.GATHER_TABLE_STATS(user,'t_part',CASCADE=>TRUE,GRANULARITY=>'ALL');


Vous pouvez maintenant interrogé à nouveau la vue User_Tab_Subpartitions et vous constaterez que les statistiques sont bien collectées.

La petite moralité de toute ca : Beaucoup pensent qu'un DBA ne sert à rien ( Spéciale dédicace aux éditeurs de logiciels !)

Les mécanismes internes d'une base de données sont rarement simple et se priver d'une compétence impliquant la partie qui engendre la majorité des problèmes de performance relève pour petite partie d'ignorance et pour grande partie d'incompétence !


LAO,








Partager cet article
Repost0
2 novembre 2008 7 02 /11 /novembre /2008 20:54
Bonsoir,

Nous voici donc au mois de novembre ! Et pour commencer (la faute à un apéro très sympa mais imprévu),il s'agira d'un petit article. Ce qui ne signifie pas qu'il n'est pas intéressant.
Il arrive souvent qu'un DBA soit amené à surveiller l'espace libre afin d'anticiper l'ajout de fichiers pour un tablespace (et au passage éviter une interruption de service)
Et la en général on trouve des scripts (bouquin, web, voir par soi même) qui donnent le tourni.
Si cela interesse quelqu'un je posterai celui exécuté par ORACLE lors de l'affichage de la vue des tablesapces dans le console Enterprise Manager.

Et pourtant depuis ORACLE 10 (release 2), il existe une vue qui donne le résultat voulu.
Pas très connu, mais grandement efficace. J'ai nommé DBA_TABLESPACE_USAGE_METRICS.

Connectons nous en system et interrogeons cette vue.


SQL> connect system/xxxxxx
SQL> SELECT * FROM DBA_TABLESPACE_USAGE_METRICS;


Quelles informations obtient-on ?
  • Le nom du tablespace
  • Espace utilisé (en nombre de blocs)
  • Taille du tablespace (toujours en nombre de blocs
  • Et enfin la colonne qui interesse le plus, le pourcentage de l'espace utilisé


 Pour information, cette liste exclue les tablespaces qui sont en lecture seule. Ce qui en soit parait logique puisqu'un tablespace en lecture seule a tout sauf vocation à s'aggrandir !

La petite morale de l'histoire est simple: Pourquoi faire compliqué, lorsqu'on peut faire simple.
Dans l'esprit de beaucoup le DBA est une bête étrange qui utilise des formules magiques.
Sans remettre en cause la complexité de certaines architectures ou problématiques, il existe bon nombres de cas, ou le bon sens et un minimum de connaissances suffisent.
C'est sur qu'un simple SELECT * FROM DBA_TABLESPACE_USAGE_METRICS, fait moins sexy qy'une requête de 60 lignes avec une demi douzaine d'UNION et de requêtes imbriquées. Mais au final le résultat sera le même.


Pour info, ci-dessous la requête fournie par TOAD pour avoir des infos sur les tablespaces.
Je vous accorde qu'elle nous donne un peu plus d'information... (datafile,infos sur le tablespace,...) mais avouez quand même que lorsque vous jetez ca à un novice, il vous prends pour un génie, alors qu'avec ma requete d'une ligne....


SELECT   t.tablespace_name "Tablespace", 'Datafile' "File Type",

         t.status "Tablespace Status", d.status "File Status",
         ROUND ((d.max_bytes - NVL (f.sum_bytes, 0)) / 1024 / 1024,
                2               ) "Used MB",
         ROUND (NVL (f.sum_bytes, 0) / 1024 / 1024, 2) "Free MB",
         t.initial_extent "Initial Extent", t.next_extent "Next Extent",
         t.min_extents "Min Extents", t.max_extents "Max Extents",
         t.pct_increase "Pct Increase",
         SUBSTR (d.file_name, 1, 80) "Datafile name"
    FROM (SELECT   tablespace_name, file_id, SUM (BYTES) sum_bytes
              FROM dba_free_space
          GROUP BY tablespace_name, file_id) f,
         (SELECT   tablespace_name, file_name, file_id, MAX (BYTES) max_bytes,
                   status
              FROM dba_data_files
          GROUP BY tablespace_name, file_name, file_id, status) d,
         dba_tablespaces t
   WHERE t.tablespace_name = d.tablespace_name
     AND f.tablespace_name(+) = d.tablespace_name  
  AND f.file_id(+) = d.file_id
GROUP BY t.tablespace_name,
         d.file_name,
         t.initial_extent,
         t.next_extent,
         t.min_extents,
         t.max_extents,
         t.pct_increase,
         t.status,
         d.max_bytes,
         f.sum_bytes,
         d.status
UNION ALL
SELECT   h.tablespace_name, 'Tempfile', ts.status, t.status,
         ROUND (SUM (NVL (p.bytes_used, 0)) / 1048576, 2),
         ROUND (  SUM ((h.bytes_free + h.bytes_used) - NVL (p.bytes_used, 0))
                / 1048576,
                2 ),
         -1,                                                 -- initial extent
            -1,                                              -- initial extent
               -1,                                              -- min extents
                  -1,                                           -- max extents
                     -1,                                       -- pct increase
                        t.file_name
    FROM SYS.v_$temp_space_header h,
         SYS.v_$temp_extent_pool p,
         SYS.dba_temp_files t,
         SYS.dba_tablespaces ts
   WHERE p.file_id(+) = h.file_id
     AND p.tablespace_name(+) = h.tablespace_name
     AND h.file_id = t.file_id
     AND h.tablespace_name = t.tablespace_name
     AND ts.tablespace_name = h.tablespace_name
GROUP BY h.tablespace_name, t.status, t.file_name, ts.status
ORDER BY 1, 5 DESC;


 LAO.
 
Partager cet article
Repost0
30 octobre 2008 4 30 /10 /octobre /2008 22:15
Bonsoir,

Histoire d'être un peu plus complete sur cette option qui permet d'éviter une ORA-01653, je tenais à préciser deux trois petites choses.

-1/ Quelles sont les opérations qui peuvent être "mise en attente".


  • Les opérations classiques telles que INSERT, UPDATE, DELETE
  • Les opérations d'import / Export
  • Les opérations DDL suivantes:
    • CREATE TABLE ... AS SELECT
    • CREATE INDEX
    • ALTER TABLE ... MOVE PARTITION
    • ALTER TABLE ... SPLIT PARTITION
    • ALTER INDEX ... REBUILD PARTITION
    • ALTER INDEX ... SPLIT PARTITION
    • CREATE MATERIALIZED VIEW
    • CREATE MATERIALIZED VIEW LOG 

-2/ Quelles sont les erreurs qui peuvent être "mise en attente".

  • La fameuse ORA-01653 (unable to extend table ... in tablespace ....
  • Sa petite soeur ORA-01654 (unable to extend index ... in tablespace ...
  • Nombre maximum d'extent atteint pour une table (ORA-01631)
  • Nombre macimum d'extent atteint pour  un index (ORA-01654)
  • Limite de quota atteinte (ORA-1536)

-3/ C'est bien beau d'avoir une telle option, mais comment savoir qu'il y a un souci.

Dans l'article précédent, on a vu qu'on pouvait de façon manuelle vérifier qu'il n'y a pas de soucis.
Je suis d'accord avec vous pour dire que c'est pas ce qu'il y a de plus pratique.
Certains traitement peuvent durer des heures, et je ne vais pas surveiller en permanence le fichier alert.log ou la table USER_RESUMABLE.

Vous vous doutez bien qu'ORACLE dans sa grande bonté a pensé à vous. Nous allons utiliser un TRIGGER !
Ouh la, j'en vois déjà qui vont me dire qu'un TRIGGER c'est sur une table..... et bien non pas uniquement, il existe des TRIGGERS qui se déclenchent au niveau base (ex: après une connexion, très pratique pour voir qui s'est connecté en SYSTEM).
Il exite un evenement qui est "AFTER SUSPEND"

exemple de trigger


CREATE OR REPLACE TRIGGER Appel_mon_gentil_dba
AFTER SUSPEND
ON DATABASE
BEGIN
....
END; 


Ensuite dans le bloc BEGIN / END, vous y mettez ce que vous voulez. Personnellemet, j'utiliserai le package UTL_SMTP qui permet à ORACLE d'envoyer des mails. Plus besoin de surveiller sa base.
Reste à surveiller sa boite mail !

Pour l'utilisation du package UTL_SMTP, je vous invite à lire la documentation ORACLE.
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/u_smtp.htm#CHDHHBJD

avec un exemple prêt à l'utilisation:
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/u_smtp.htm#i1006675

Attention quand même à modifier les informations concernant le serveur SMTP et les adresses emails.

Bonsoir & à bientôt,

LAO. 
Partager cet article
Repost0
28 octobre 2008 2 28 /10 /octobre /2008 20:05
Bonsoir,

Ce soir on va mettre un peu de coté notre "big table" (mais c'est promis, on y revient très bientôt).
En revanche, je vais vous parler d'un petit soucis qui peut être agacant.
La fameuse ORA-01653 !

Qu'est ce que le ORA-01653 ?
C'est ce qui arrive lorsqu'un tablespace est défini avec la clause AUTOEXTEND à OFF et que l'on tente d'inserer dans une table alors qu'il n'y a plus de place (ou durant un import).

 Et plus exactement, cela donne ORA-01653 : Impossible d'étendre la table .... de 8 dans le tablespace ....

Bref que du bonheur, surtout si c'est un traitement qui a pris plusieurs heures, et qu'il va donc falloir recommencer.

Alors bien sur, on peut mettre en place des systemes d'alerte avec des seuils (remplissage à 80 %) pour éviter d'être pris au dépourvu. N'empêche que cela peut quand même arriver....

Et alors ? Que faire ?

Et bien comme pour dans de nombreux cas, ORACLE à prévu de pouvoir palier (en partie du moins) à ce genre de soucis. 

Il existe un paramètre qui permet lorsque que l'on arrive à cette limite de taille de figer le traitement plutôt que de renvoyer une erreur.

Ca paramètre a un nom : RESUMABLE_TIMEOUT
Et par défaut sa valeur est 0. Ce qui signifie que le traitement est stoppé avec la fameuse erreur.

Mais arretons de parler, et passons à la pratique.


/*Creation d'un tablespace de petit taille*/
SQL> CONNECT SYSTEM/xxxxx
SQL> CREATE TABLESPACE TBS_1 DATAFILE 'c:\oracle\product\oradata\oradb\tbs01.dbf' SIZE 1M AUTOEXTEND OFF;

/* On donne les droits à l'utilisateur LAO sur ce nouveau tablespace*/
SQL> ALTER USER LAO QUOTA UNLIMITED ON TBS_1;

/* Creation d'une table */
SQL> CONNECT LAO/LAO
SQL> CREATE TABLE T1 (i number,j number);

/* Remplissage de la table*/
SQL> BEGIN
SQL> FOR l IN 1..1000000 LOOP
SQL> INSERT INTO T1 VALUES (l,l);
SQL> END LOOP;
SQL> END;
SQL> /



Ce qui devait arriver arriva:==> ORA-01653 ......

Modifions donc la valeur du parametre RESUMABLE_TIMOUT pour la session


SQL> ALTER SESSION SET RESUMABLE_TIMEOUT=120 (l'unité est la seconde)


Et ....erreur, une ORA-01031 qui nous indique que nous n'avons pas le droit de faire cela.

Que cela ne tienne, donnons nous les droits.
On se reconnecte en system.


SQL> CONNECT SYSTEM/xxxxx
SQL> GRANT RESUMABLE TO LAO;



On peut donc repartir en user normal.


SQL> CONNECT LAO/LAO
SQL> ALTER SESSION SET RESUMABLE_TIMEOUT=3600;
Session modifée.



Relancons le script de remplissage.


SQL> BEGIN
SQL> FOR l IN 1..1000000 LOOP
SQL> INSERT INTO T1 VALUES (l,l);
SQL> END LOOP;
SQL> END;
SQL> /



Que se passe t-il ? RIEN !
Alors que la première fois le traitement était parti en vrille quasi tout de suite, il semble ne rien se passer.
Et en fait, il ne se passe rien. Et il continuera de ne rien se passer pendant 3600 secondes. Au dela de ce délai, le traitement renverra une erreur.

Comment être sur de cela ?
Plusieurs moyens

  • Via votre outil d'administration préféré, vérifier qu'il n'y a plus de place dans le tablespace TBS_1
  • Aller jeter un oeil dans le fichier ALERT.log qui se trouve dans ORACLE_HOME\admin\SID\bdump\
  • avec une autre session jeter un oeil dans la vue USER_RESUMABLE


Je passe la première méthode.

Alert.log

SI on va  à la fin du fichier, on l'information suivante: 
ORA-01653 : unable to extend table LAO.T1......
Statement in resumable session 'user LAO(61), session 148 was suspended....

C'est pas beau ! y a plus qu'a aggrandir notre fichier(ou en ajouter un nouveau) et le traitement repart.
L'inconvenient avec ce moyent, c'est qu'il faut avoir accès au fichier alert.log et donc au serveur proprement dit.

USER_RESUMABLE

en se connectant dans une nouvelle session en LAO.


SQL> SELECT Session_ID,Status,Timeout,Sql_Text,Error_msg FROM User_Resumable;


On obtient:
Sessio_ID => 148
Status      => SUSPENDED
Timeout   => 3600
Sql_Text   => INSERT INTO T1 VALUES (:B1,:B1)
Error_Message => ORA-01653

Même punition et même remède.


On se connecte en system


SQL> CONNECT SYSTEM/xxxxx
SQL> ALTER TABLESPACE ADD DATAFILE 'c:\oracle\product\oradata\oradb\tbs02.dbf' SIZE 100M AUTOEXTEND OFF;



Et la, oh magie, le traitement reprends...
Vous pouvez d'ailleurs le constater en refaisant le select sur la table User_Resumable (en LAO/LAO)
Le status aura la valeur NORMAL.

En conclusion, je pense que cette option est sympa et qu'il faut l'exploiter. Plutôt que de modifier la valeur au niveau session on peut également modifier la valeur pour la base.
Dans ce cas, il conviendrait de trouver un moyen d'automatiser l'alerte pour que le dba soit au courant qu'un traitement est en attente (recevoir un mail par exemple). Mais ceci est une autre histoire qui fera peut être l'objet d'un nouvel article.


@ bientôt,

 LAO
Partager cet article
Repost0