Rechercher sur arkzoyd.com

29 septembre 2007

Quand les problèmes commencent... /* Part 3 */

Mes premier et deuxième posts sur ce thème sont liés au travail avec Oracle parce qu'il y avait matière. Est-ce que je mérite de plus en plus mon salaire de DBA ? Je n'en sais rien mais en tous cas, l'expérience du jour (ou plutôt de la nuit) pose plusieurs questions quant à ma capacité à vivre dans la réalité ; j'explique !

Depuis bientôt 1 mois, le déménagement se faisant de manière assez compliquée, je suis seul avec nos fils et fille à Ottawa ! Et donc, j'"assume" les enfants, le boulot et les astreintes... Toujours est-il que je termine cette semaine d'astreinte ce week-end et que les courses sont le dernier de mes soucis. Comme il y a toujours de la place pour s'améliorer, la planification de la poudre pour la machine à laver la vaisselle à lamentablement échouée hier soir. S'est ouvert pour moi, un de ces choix cornéliens :
  • Dois-je faire la vaisselle à la main ?
  • Dois-je laisser tourner le lave vaisselle sans poudre ?
Bref, ce qui me connaissent savent que "j'aime bien sortir du cadre". Et me voila parti pour une nouvelle idée ! Je nous en dirai pas plus, si ce n'est, pour vérifier vos hypothèses chez vous, que (1) ma machine à laver la vaisselle est une MOFFAT, même si j'imagine que l'effet est (machine à laver la vaisselle)-indépendant et que (2) j'ai passé un bon moment ce matin pour nettoyer le 50 cm d'épaisseur de mousse qui restait dans la cuisine.

PS : Si vous travaillez pour la protection des enfants, inutile de passer à la maison ; quoique ?

26 septembre 2007

J'ai dit "OFFLINE" !

Juste pour que vous compreniez bien l'intérêt du post précédent à propos de DBMS_REDEFINITION : ALTER TABLE MOVE sur autre chose qu'un IOT nécessite que l'activité soit arrêtée. Voici pourquoi !

Supposons une petite table...
create table demo(
id number,
text varchar2(1),
constraint demo_pk
primary key(id));

insert into demo values (1,'A');

commit;
Déplacer votre segment

Vous pouvez avoir envie de reconstruire/déplacer cette petite table ! Par exemple, pour une sombre histoire de "High Watermark" dans les fichiers de données que vous voulez réduire parce le DBA qui vous a précédé à fait n'importe quoi !

Pourquoi ne pas utiliser ALTER TABLE ... MOVE puisque au pire, les sessions devrait attendre quelques secondes ? Enfin, c'est ce qu'on peut imaginer ! Et que l'exemple qui suit semble montrer :
Session 1 :
-----------
insert into demo values (2,'B');

Session 2 :
-----------
--
-- Note : This is a 11g feature and 10g
-- ------ would require you'd use :
-- "lock table ... in exclusive mode"
alter session set
ddl_lock_timeout = 1000;

alter table demo move
tablespace users;

Session 3 :
-----------
update demo
set text='B'
where id=1;
Remarquez que dans cet exemple, la session 1 bloque la session 2 qui elle-même bloque la session 3. Si vous validez ou annulez la première session. la session 2 reconstruit la table immédiatement et la session 3 (Puisqu'il s'agit d'un ordre DDL) est exécutée des que la session 2 termine son operation... soit presque immédiatement ;
Session 1 :
-----------
commit;

Session 2 :
-----------
Table altered.

Session 3 :
-----------
1 row updated.
il n'y a pas d'erreur, victoire ?

Maintenant un cas moins favorable !

En fait, il faut savoir que quand la table est reconstruite avec un "ALTER TABLE ... MOVE", les index ne suivent pas deviennent unusable ! La requête suivante permet de s'en persuader :
select index_name, status
from user_indexes
where table_name='DEMO';

INDEX_NAME STATUS
---------- --------
DEMO_PK UNUSABLE
Et par conséquent, les ordres qui doivent valider la contrainte primary key echouent comme ci-dessous :
insert into demo values(3,'C')
*
ERROR at line 1:
ORA-01502: index 'DEMO.DEMO_PK' or partition
of such index is in unusable state
Et alors ? Il suffit de reconstruire l'index, non ?
alter index demo_pk
rebuild;

Index altered.

insert into demo values(3,'C');

1 row created.
Bon et bien facile !

Il suffit de faire le rebuild des index uniques juste après faire le "alter table... move" !

Mais c'est plus facile à dire qu'à faire ; les ordres DDL ne peuvent pas être exécutés dans la même transaction ! La seule manière que j'ai trouvé pour l'instant, c'est bien d'arrêter l'application ou au moins de l'empêcher pendant cette période de faire des opérations DML. La commande "alter table read only" pourrait être utile, si seulement mon application savait gerer :
ORA-12081: update operation not allowed
on table "DEMO"."DEMO"
Bien sur, on peut passer la base de données en mode QUIESCE, ce qui assurera qu'il y a pas de transaction en cours... remarquez que ça reviens au même meme si c'est une operation technique sur la base de données et est sans doute plus rapide (Quand ça marche !).

Conclusions :
  • DBMS_REDEFINITION, c'est bien, même pour des petites tables ! Si seulement je pouvais me débarrasser de ces bases 9i
  • Je ne vois pas de moyen de s'en sortir élégamment dans ce cas avec ALTER TABLE... MOVE ; et vous ?
Notes pour la suite :
  • La raison pour laquelle les index deviennent "unusable" est assez évidente : comme ceux ci contiennent les rowid, le fait que les données de table se déplace invalide de fait toutes ces valeurs dans les index ! Comme je l'ai déjà dit, il faudrait reconstruire les index dans la foulée en garantissant que les ordres au moins DML (Et les selects pour les plans) soient bloqués sur cette table le temps du changement. En dehors d'une syntaxe que je ne connais pas, je ne vois pas comment ça serait possible en 11g Release 1.
  • La raison pour laquelle c'est différent avec les IOT, est également évidente : les index sur les IOT ne contiennent pas le ROWID des lignes mais la clé primaire de l'IOT ; Une preuve de plus que les IOT peuvent être un outil intéressant si le TPC-C ne suffisait pas.

23 septembre 2007

2-3 trucs à propos de DBMS_REDEFINITION

Ça fait des mois que ce post traîne parmi les 70 sujets en cours de rédaction... presque fini mais pas encore tout à fait : Cette fois j'irai au bout !

Avertissement : Testez toujours les opérations que vous allez mettre en œuvre avec DBMS_REDEFINITION et ne prenez jamais comptant mes propos ! En particulier, notez que la majorité des tests de ce post ont été réalisés avec Oracle 11.1.0.6 sous Linux 32bits et que d'autres versions peuvent avoir des comportements différents.

DBMS_REDEFINITION est sans doute un des packages que j'utilise le plus, surtout depuis 10g et sa capacité à "redéfinir" (déplacer, reconstruire, transformer) une seule partition aussi facilement qu'une table avec 0 indisponibilité. Zéro ? quoique ! La faute aux utilisateurs qui ne veulent pas arrêter leur système ? Pas seulement, DBMS_REDEFINITION permet aussi de conserver plus de données en ligne en déplaçant des partitions sur autre type de stockage et sans passer le tablespace en lecture seule ni de manipuler ASM ou un Volume Manager comme Veritas.

Avant de dire de quoi parle ce post, je vous renvoie à ces 2 URLs. Notez que la première est vraiment bien faite :
Encore un petit conseil : Si vous trouvez que LiveReorg est puissant, regardez bien DBMS_REDEFINITION et d'autres outils comme le "split partition" et vous vous rendrez compte que vous pouvez faire pareil avec les licences EE !

Quelles sont les questions qu'il faut se poser quand vous utilisez ce package ? C'est justement de quoi ce post parle à travers un exemple simple et un ensemble de questions.

Question n°1 : Comment ça marche ?

Le principe de "redéfinition" d'une table ou une partition est très simple. Alors que votre table est accédée par des ordres DML, vous allez :
  • Etape 1 : Votre table est en ligne
  • Etape 2 : Démarrer la redéfinition, c'est à dire
    • Créer une table vide dite "intermédiaire" avec vos nouvelles propriétés (PCTFREE, Nouveau Tablespace, Nouvelle taille de colonne ou tout ce que vous voulez ou presque)
    • Définir des règles de correspondance entre les colonnes de votre table ou partition originale et la table cible (si les noms des colonnes ou les formats sont différents par exemple)
    • Démarrer la capture, les modifications sur la table originale seront conservées dans un espace dédié pendant que la table intermédiaire sera alimentée par un select correspondant au moment du démarrage de la capture
  • Etape 3 : Modification et synchronisation intermédiaire. Vous pouvez dans cette étape
    • Construire automatiquement (ou manuellement) l'ensemble des contraintes, index, triggers et grants que vous voulez sur votre table intermédiaire. Ils seront conservés lors de l'étape 4.
    • Synchroniser les modifications capturées pour diminuer le temps d'indisponibilité associé à l'étape 4
  • Etape 4 : la bascule
    • La table originale est verrouillée.
    • Les noms de la table intermédiaire et la table ou partition originale sont échangés
    • L'ensemble des clés étrangères et des triggers vers les 2 tables sont désactivés/activés à condition qu'ils aient été migrés automatiquement à l'étape 3.
    • L'activité peu reprendre
L'étape 4 bloque avec un verrou exclusif la table/partition originale. Attention donc si l'application pour une raison ou une autre pose également des verrous qu'elle ne relâche pas ! Le temps d'indisponibilité si vous avez au préalable appliqué les modifications est assez cours et il n'est pas besoin de déconnecter les utilisateurs qui devront simplement attendre que l'opération d'"échange" de la table intermédiaire avec la table ou partition originale soit terminée.


Question n°2 : Doit-on vraiment utiliser DBMS_REDEFINITION ?

Surtout pas ! Enfin, s'il y a un moyen de faire autrement bien sur ! Pourquoi ?
  • Parce que DBMS_REDEFINITION nécessite de dupliquer les données dans un autre espace pendant la durée de de l'opération. Un "alter table move" aussi, me direz vous !
  • Parce que c'est plus compliqué qu'un "alter table move" !
  • Parce que ça génère un surplus d'activité sur la table du fait de l'activation de la capture des changements pendant la phase de transition d'une table à l'autre
  • Parce que c'est plus souvent inutile qu'on pense ! Quel est l'impact d'après vous de 10 000 "chained rows" dans une table pour votre application ? Et si ça vous gène, il est sans doute possible avec DELETE puis INSERT des lignes chaînées de les supprimer. Pour les repérer, utilisez l'ordre ANALYZE TABLE ... CHAINED ROWS et faites attention aux foreign keys surtout avec ON DELETE CASCADE.
  • Parce qu'il y a souvent des alternatives :
    • SHRINK SPACE COMPACT est un bon exemple quand c'est utilisable.
    • Vous pouvez faire des ONLINE MOVE sur une IOT !
    • Vous pouvez peut-être persuader le métier d'arrêter son application
    • Vous pouvez charger une valeur par défaut en batch dans une colonne que vous ajoutez
    • Sûrement beaucoup d'autres cas que je n'imagine même pas
  • Parce qu'il a des cas ou vous ne pouvez pas : Par exemple, si vous avez un Materialized View Log sur votre table ; remarquez qu'en 11g, ce cas n'est plus une limite d'après la documentation.
  • Parce que vous n'utilisez pas la version "Enterprise Edition". Désolé les amis ; et ça m'arrive aussi !
Maintenant que vous avez à peu prêt toutes les bonnes raisons de ne pas utiliser DBMS_REDEFINITION (J'en oublie ?), sachez vous pouvez les éliminer (ou non) et choisir d'utiliser ce package. Et ne dites pas : "Je n'utilise pas DBMS_REDEFINITION parce que c'est compliqué... Ce n'est pas vrai !"

Question n
°3 : Qu'est ce que vous voulez redéfinir ?

Cette question peut vous emmener loin... En réalité, même si, vous voulez redéfinir toute votre base de données (oubliez SYS et SYSTEM), il suffit de considérer que vous allez redéfinir séparément chacune de vos tables (ou partitions) et le problème devient très simple :
  • Si après vous voulez vous organiser pour tout faire en même temps, parce que, par exemple votre application doit migrer simultanément pour gérer des colonnes plus grandes, c'est un autre problème. Dans ce cas vous terminerez la "redefinition" de toutes vos tables en même temps et en quelques minutes. Pour développer vos scripts, raisonnez table par table et partition par partition, ça sera très simple
  • Remarquez bien que :
    • Les index et contraintes associées doivent être reconstruits avec la table. Ça peut être fait automatiquement par DBMS_REDEFINITION ou vous pouvez aussi les modifier manuellement
    • Les triggers et les contraintes référentielles des autres tables vers cette table sont logés à la même enseigne que les index, sauf qu'ils seront activés lors de la dernière phase de l'opération si vous utilisez la gestion automatique des dépendances.
Remarque Importante : "Toute chose n'étant vrai que si son contraire l'est aussi (mon adage favori !)" : il y a des cas pour lesquels vous ne pourrez pas considérer votre problème comme un ensemble de sous problèmes indépendants et il faudra obligatoirement modifier un ensemble de tables/partitions simultanément. Par exemple :
    • Si vous modifiez la taille et/ou le contenu d'une clé primaire référencée par une clé étrangère, vos devrez modifier l'ensemble des colonnes simultanément puisqu'elles sont dépendantes
    • Si vous redéfinissez une table qui contient un LOB stocké dans une table overflow, il faudra redéfinir les 2 tables simultanément
    • Si vous redéfinissez une partition d'une table avec des index globaux, ils seront "UNUSABLE" après l'échange des partitions
Question n°4 : La table/Partition doit-elle avoir une clé primaire ?

Il y a deux manières, pour DBMS_REDEFINITION, de suivre à quelle ligne s'applique une modification sur la table/partition originale :
  • Soit avec la clé primaire (La solution que vous préférerez, sauf si ce n'est pas possible)
  • Soit avec ROWID. Dans ce cas, une colonne (M_ROW$$) et un index (I_SNAP$_<TABLE_NAME>) seront ajoutés sur la table intermédiaire pour stocker et rechercher le ROWID. Cette deuxième méthode est donc plus consommatrice et créée une colonne qui est marquée NOT USED automatiquement si le paramètre COMPATIBLE est supérieur ou égal à 10.2.
La réponse est donc NON mais si votre table n'a pas de clé primaire, la méthode que vous utiliserez sera sans doute différentes.

Question n
°5 : Puis-je vraiment utiliser DBMS_REDEFINITION avec ma table ?

Le meilleur moyen de le savoir, c'est de le demander. Pour ça, vous allez utiliser la procédure CAN_REDEF_TABLE. Pour cet exemple, nous allons modifier la table SCOTT.DEPT !
exec dbms_redefinition.can_redef_table(-
'SCOTT', -
'DEPT', -
DBMS_REDEFINITION.CONS_USE_PK)

PL/SQL procedure successfully completed.
Dans notre exemple,
DBMS_REDEFINITION.CONS_USE_PK signifie que l'on veut s'appuyer sur la clé primaire. On pourrait, s'il n'y avait pas de clé primaire, s'appuyer sur le ROWID avec DBMS_REDEFINITION.CONS_USE_ROWID. Si vous ne pouvez pas redéfinir la table une erreur est retournée avec la raison associée.

Dans l'exemple qui suit
on regarde s'il est possible de redéfinir la partition SALES.SALES_Q4_2003 du schéma exemple SH. Comme généralement les tables de fait ne sont pas de clé primaire, dans ce cas, on utilisera le ROWID. Notez que ce dernier exemple ne fonctionne qu'à partir de 10g :
exec dbms_redefinition.can_redef_table(-
'SH', -
'SALES', -
DBMS_REDEFINITION.CONS_USE_ROWID, -
'SALES_Q4_2003')

PL/SQL procedure successfully completed.
Question n°6 : Quelle doit être la structure de la table/partition intermédiaire que je vais créer ?

Vaste question ! Pourquoi vous voulez utiliser DBMS_REDEFINITION d
éjà ? Vous pouvez changer le type, le contenu, le nom des colonnes. Vous pouvez changez le tablespace, les clauses de stockage, les index, les triggers. Tout ce que vous voulez ! Je serai donc bien malin de vous dire comment doit être votre table à la fin.

Il faut toutefois noter quelques restrictions
à la manière dont vous voulez que vos tables évoluent :
  • Si vous ne réorganisez qu'une partition de la table, seules les clauses de stockage peuvent changer et vous ne pouvez pas changer une colonne de type par exemple !
  • La relation entre les colonnes de la table d'origine et cible doit être simple et ne peut pas mettre en oeuvre des requetes SQL par exemple (Quoique!)
  • Le plus simple pour faire évoluer votre table, c'est encore de capturer le DDL d'origine avec la commande DBMS_METADATA.GET_DDL comme ci-dessous :
var output clob;

exec :output:=dbms_metadata.get_ddl('TABLE',-
'EMP',-
'SCOTT')
set pages 1000
set long 9999
print output

OUTPUT
------------------------------------------------------------------------
CREATE TABLE "SCOTT"."DEPT" (
"DEPTNO" NUMBER(2,0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS" ENABLE
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
Supposons donc que nous voulions créer une nouvelle table DEPT avec un PCT_FREE de 80, nous allons créer notre future "DEPT" table avec les informations que nous désirons voir modifiées et avec un nom différent (On pourra utiliser $INT pour dire qu'il s'agit d'une table intermédiaire) :
CREATE TABLE SCOTT.DEPT$INT (
DEPTNO NUMBER(2,0),
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT PK_DEPT$INT PRIMARY KEY (DEPTNO)
USING INDEX TABLESPACE USERS
) PCTFREE 80
TABLESPACE USERS;

Table created.
Question n°7 : Comment mettre en relation les colonnes de la table d'origine et les colonnes de la table modifiée ?

Et bien cette étape est réalisée lors de l'initialisation de la redéfinition grâce au paramètre COL_MAPPING de la procédure START_REDEF_TABLE. Et oui, l'étape suivante une fois que vous avez créé la table intermédiaire consiste à démarrer la redéfinition avec cette procédure; Si vous voulez changer le nom des colonnes ou transformer leur contenu, il faudra utiliser ce paramètre.

le contenu du paramètre peut être NULL ce qui indique que le nom et le contenu des colonnes ne change pas. Dans ce cas, le type peut changer
à condition que les données soient compatibles avec le nouveau type. Si le paramètre COL_MAPPING n'est pas NULL, il doit alors indiquer le contenu de ce que serait une clause SELECT sur la table d'origine pour alimenter la table intermédiaire.

Dans notre cas, les colonnes restent identiques, nous pourrions utiliser NULL comme valeur pour le paramètre COL_MAPPING. Juste pour le geste, voila comment démarrer la redéfinition avec le paramètre positionné malgré tout :
exec DBMS_REDEFINITION.START_REDEF_TABLE( -
'SCOTT', -
'DEPT', -
'DEPT$INT', -
COL_MAPPING => 'deptno, dname, loc', -
options_flag => DBMS_REDEFINITION.CONS_USE_PK)

PL/SQL procedure successfully completed.
Cette opération, comme vous pouvez facilement le vérifier, démarre le chargement initial de la table intermédiaire :
select count(*)
from scott.dept$int

COUNT(*)
--------
4
Question n°8 : Comment créer les contraintes/index et autres objets dépendants ?

Vous pouvez copier les objets qui dépendent de votre table d'origine sur la table temporaire des maintenant ou après avoir commencé la redéfinition. A travers objets dépendants, on entend :
  • Clé primaire ou secondaire (Remarquez que si vous vous appuyez sur une de ces clés, il faut qu'elle soit créées avant de commencer la redéfinition)
  • Contrainte d'unicité et not null
  • Check
  • Clés étrangère à partir ou à destination de la table
  • Index
  • Triggers
  • Grants
  • (En 11g) Materialized View Logs
Pour ces opérations 3 possibilités mais notez que (1) Vous ne pouvez pas utiliser les méthodes automatiques ou enregistrer les objets dépendants tant que vous n'avez pas commencé la redéfinition; (2) vous ne pourrez pas créer de clés étrangères qui soit "enabled" (vous comprendrez facilement !) ; et (3), créer les index une fois la table alimentées peut avoir du sens en terme de performance. Les 3 possibilités sont donc :
  1. Créer manuellement les objets dépendants et gérer leur état manuellement (e.g : disable, validated...)
  2. Créer manuellement les objets dépendants et les mettre en correspondance avec les objets d'origine avec DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT
  3. Créer automatiquement les objets depuis la table d'origine avec la procédure DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS
Remarque importante : En 9i, vous ne disposez que de la première possibilité !

Dans l'exemple qui suit nous allons utiliser la méthode 3 pour créer automatiquement la clé étrangère entre EMP et DEPT$INT. Nous utiliserons la méthode 2 pour enregistrer manuellement la clé primaire PK_DEPT$INT parmi les objets dépendants. Notez que si vous ne le faite pas, la contrainte et l'index ne seront pas renommées à la fin de la redéfinition...
var numerr number;
exec DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(-
'SCOTT', -
'DEPT', -
'DEPT$INT', -
ignore_errors => true, -
num_errors => :numerr);

print numerr

NUMERR
------
2
La raison des 2 erreurs peut être facilement expliquée par le fait que nous avons créé une clé primaire et l'index associé lors de la création de la table. Pour cela, interrogeons DBA_REDEFINITION_ERRORS comme ci-dessous :
col OBJECT_TYPE format a15
col OBJECT_OWNER format a15
col OBJECT_NAME format a15
select OBJECT_TYPE,
OBJECT_OWNER,
OBJECT_NAME,
DDL_TXT
from dba_redefinition_errors

OBJECT_TYPE OBJECT_OWNER OBJECT_NAME
------------ --------------- ---------------
DDL_TXT
--------------------------------------------------------------------------------
INDEX SCOTT PK_DEPT
CREATE UNIQUE INDEX "SCOTT"."TMP$$_PK_DEPT0" ON "SCOTT"."DEPT$INT" ("DEPTNO")
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"

CONSTRAINT SCOTT PK_DEPT
ALTER TABLE "SCOTT"."DEPT$INT" ADD CONSTRAINT "TMP$$_PK_DEPT0" PRIMARY KEY ("DEP
TNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS" ENABLE NOVALIDATE
Pour connaître les objets qui sont maintenant gérés par DBMS_REDEFINITION, vous pouvez interroger la vue DBA_REDEFINITION_OBJECTS :
col TYPE   format a10
col OWNER format a6
col NAME format a9
col IOWNER format a6
col INAME format a16
select OBJECT_TYPE TYPE,
OBJECT_OWNER OWNER,
OBJECT_NAME NAME,
INTERIM_OBJECT_OWNER IOWNER,
INTERIM_OBJECT_NAME INAME
from dba_redefinition_objects;

TYPE OWNER NAME IOWNER INAME
---------- ------ --------- ------ ----------------
TABLE SCOTT DEPT SCOTT DEPT$INT
CONSTRAINT SCOTT FK_DEPTNO SCOTT TMP$$_FK_DEPTNO0
Enfin, il est possible d'ajouter la clé primaire et l'index créés avant le démarrage de la redéfinition à l'aide de DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT comme ci-dessous :
exec dbms_redefinition.register_dependent_object( -
'SCOTT', -
'DEPT', -
'DEPT$INT', -
DBMS_REDEFINITION.CONS_INDEX, -
'SCOTT', -
'PK_DEPT', -
'PK_DEPT$INT');

PL/SQL procedure successfully completed.

exec dbms_redefinition.register_dependent_object( -
'SCOTT', -
'DEPT', -
'DEPT$INT', -
DBMS_REDEFINITION.CONS_CONSTRAINT, -
'SCOTT', -
'PK_DEPT', -
'PK_DEPT$INT');

PL/SQL procedure successfully completed.

select OBJECT_TYPE TYPE,
OBJECT_OWNER OWNER,
OBJECT_NAME NAME,
INTERIM_OBJECT_OWNER IOWNER,
INTERIM_OBJECT_NAME INAME
from dba_redefinition_objects;

TYPE OWNER NAME IOWNER INAME
---------- ------ --------- ------ ----------------
TABLE SCOTT DEPT SCOTT DEPT$INT
CONSTRAINT SCOTT FK_DEPTNO SCOTT TMP$$_FK_DEPTNO0
INDEX SCOTT PK_DEPT SCOTT PK_DEPT$INT
CONSTRAINT SCOTT PK_DEPT SCOTT PK_DEPT$INT
Et nous voila fin prêt pour la suite...

Question n
°9 : Comment faire des synchronisations intermédiaires ?

Cette question peut paraître saugrenue mais dans la réalité, reconstruire l'ensemble des dépendance peut être long et beaucoup de transactions peuvent être appliquées sur la table d'origine pendant la phase pr
écédente... Pour réduire le temps de transition, ou simplement pour améliorer vos phases de tests, faire des synchronisation intermédiaire, y compris juste avant de basculer la table intermédiaire avec la table/partition d'origine sont une bonne pratique. Pour cela, vous allez utiliser la procédure DBMS_REDEFINITION.SYNC_INTERIM_TABLE comme ci-dessous :
exec dbms_redefinition.sync_interim_table( -
'SCOTT', -
'DEPT', -
'DEPT$INT')

PL/SQL procedure successfully completed.
Il est facile de voir l'effet de cette fonction, si par exemple, vous avez inséré, modifié ou supprimé une ligne entre le début de l'utilisation de DBMS_REDEFINITION et le moment de la synchronisation intermédiaire.

Question n°10 : Que se passe-t-il si on a des transactions en cours lorsque l'on finit d'utiliser DBMS_REDEFINITION ?

Pour répondre
à cette question, nous allons terminer la redéfinition avec DBMS_REDEFINITION.FINISH_REDEF_TABLE, mais avant, nous allons ouvrir une nouvelle session SQL*Plus et exécuter l'ordre suivant (En veillant à laisser la session ouverte)
select *
from scott.dept
where deptno=10
for update;

DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
Et, comme prévu, nous allons terminer, à partir d'une autre session la redefinition
exec dbms_redefinition.finish_redef_table( -
'SCOTT', -
'DEPT', -
'DEPT$INT')
Heureusement avec SQL*Plus il est simple d'abandonner la procédure car, l'intention de poser un verrou exclusif sur la table est donnée et les nouvelles transactions sont bloquées. J'appuie vite sur <Ctrl+C>
*
ERROR at line 1:
ORA-42012: error occurred while completing the redefinition
ORA-01013: user requested cancel of current operation
ORA-06512: at "SYS.DBMS_REDEFINITION", line 78
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1664
ORA-06512: at line 1
C'est pour cette raison qu'il est sans doute préférable :
  • De superviser les verrous posés depuis longtemps avant de terminer une redéfinition
  • D'utiliser un LOCK TABLE ... IN EXCLUSIVE MODE WAIT 3 avant d'utiliser une commande comme celle-ci.
Annulez l'ordre SELECT FOR UPDATE de votre session blocante :
rollback;

Rollback complete.
Puis dans la seconde session, executez DBMS_REDEFINITION.FINISH_REDEF_TABLE avec le lock exclusive wait dans le même block PL/SQL:
begin
lock table scott.dept in exclusive mode wait 3;
dbms_redefinition.finish_redef_table(
'SCOTT',
'DEPT',
'DEPT$INT');
end;
/

PL/SQL procedure successfully completed.
Bon en l'occurence dbms_redefinition.finish_table_redef opère un ordre DDL qui libère le lock TM pose par la commande LOCK TABLE mais en général, n'hésitez pas à ajoutez la commande rollback avant la fin de votre code PL/SQL

Question n°11 : Qu'est-ce qui peut changer après l'utilisation de DBMS_REDEFINITION et quel peut-être l'impact de ces changements ?

Je n'ai pas trouvé de documentation officielle à ce sujet mais voilà au moins ce à quoi il faut être attentif. Il se peut que j'en oublie alors soyez attentif à tout et dites moi si vous trouvez autre chose (même le plus petit détails comme un droit !)

A) Si vous faites des changements sur les objets d
épendants et que vous ne gérez pas la transition via DBMS_REDEFINITION (Ce qui est toujours le cas avant 10g), il faut gérer manuellement ces objets et en particulier il faut activer (ENABLE) :
  • Les triggers
  • Les contraintes
  • Les Materialized View Log
D'autres part, vous noterez également que les statistiques ne sont pas importées et que les objets intérimaires gardent leur nom (Vous pouvez le renommer manuellement).

B) Si vous faites les changements sur les objets dépendant via DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS, il faut noter que les contraintes sont "NO VALIDATED" et que, j'en ai déjà parlé, ça peut avoir un impact sur les plans d'exécution. N'hésitez pas à les valider dès que vous le pouvez (Immediatement pour NOT NULL, plus tard pour les FK...)

C) Si vous utilisez la redéfinition avec le ROWID, une colonne qui contient le rowid est ajoutée a la table. Faites y d'autant plus attention si COMPATIBLE<=10.1 puisque un "SELECT *" ne ramenera pas le même nombre de colonnes. Enfin avec COMPATIBLE >= 10.2, ce n'est plus le cas et la colonne est masquée mais elle est toujours là ! Vous pouvez toujours la supprimée après coup.

D) En 9i au moins, les statistiques et dans tous les cas bien sur les structures physiques. Il n'est pas improbable que cette opération aboutisse à des changements de plan d'exécution, souvent recherchés et parfois non

F) Les objets dépendant sont invalidés (vues, packages PL/SQL) et selon l'utilisation qui en est faite, il est possible voir probable que votre application rencontre des erreurs lors de l'appel de FINISH_TABLE_REDEF !

Question
n°12 : Est-ce terminé ?

En fait, non ! N'oubliez pas de supprimer la table intermédiaire qui est en fait la table d'origine que vous n'utilisez plus ainsi que toutes ses dépendances :
drop table scott.dept$int
cascade constraints
purge;

Table dropped.
Question n°13 : Comment recommencer de zéro ?

Si pour n'importe quelle raison, vous devez arrêter en cours de route la redéfinition de vos objets, utilisez la fonction DBMS_REDEFINITION.ABORT_REDEF_TABLE. Vous pourrez alors supprimer tous les objets intermédiaires créés et recommencer de zéro ou pas !

Question n
°14 : A quoi faire attention encore ?

En arrière plan, lorsque commence une redéfinition, la table intermédiaire devient une vue matérialisée de la table d'origine et un "MV Log" est ajoutée à la table d'origine en mode "fast refresh". Vous en déduirez simplement comment suivre l'évolution des captures sur la table d'origine ! Voila et même si, comme moi, vous avez une confiance aveugle en Oracle, il est sans doute préférable de comparer l'ensemble des informations dont vous disposez avant et après les modifications et surtout de tester que votre application supporte bien de tels changements.

Voila c'est tout pour l'instant ! Si jamais j'avais oublié d'autres différences générées par DBMS_REDEFINITION (cf question 11), n'hésitez pas à commenter ce post ! A part ça, je souhaite simplement que ce post puisse vous servir d'aide mémoire pour la prochaine utilisation de ce package.

20 septembre 2007

Un autre lecture fascinante...

Il y a quelques temps, je disais ici à quel point, lire les rapports du TPC sont intéressants... En fait, il y a une autre documentation encore plus intéressante !

Imaginez que mon bug du jour (tout évolue) est corrigé en 10.2.0.4. Et non, ce n'est pas encore disponible ! Par curiosité j'ai parcouru la note 401436.1. Ça peut faire peur ; et je crois que j'ai peut-être trouvé l'explication à un autre phénomène jusqu'ici que je n'expliquais pas !

19 septembre 2007

Les ailes de la renommées

Juste pour partager avec vous... Si vous arrivez sur ce site, vous pouvez probablement vous situer grâce à la carte ci-dessous :


C'était prévisible me direz vous puisque j'écris en français. Ce qui l'est moins c'est que le contenu de ce site intéresse les anglophones aussi. Merci donc à Dave Edwards pour avoir traduit mon dernier article a propos de RAC 11g en anglais ! Bien sur, ça m'interpelle et vous qu'en pensez vous ?

Faire le lien entre un programme (process) et ses connexions TCP/IP

Je suppose que tout le monde connait et que ce post sera inutile, sauf à moi-même. Trouver quel est le processus qui utilise une connexion TCP/IP est parfois utile et en l'occurrence, netstat peut afficher cette information.

Sous Linux :
netstat -p

Active Internet connections (w/o servers)
PID/Program name Proto Recv-Q Send-Q Local Address Foreign Address
27171/skype tcp 0 0 arkzoyd:58688 d235-159-172.home:21773
27173/pidgin tcp 0 594 arkzoyd:52721 el-in-f125.:xmpp-client
Sous Windows :
netstat -o
Pour des raisons que vous comprendrez, je n'ai pas de copie d'écran mais croyez moi, j'ai essayé sur le PC de ma femme hier, ça marche ! En revanche, il vous faudra sans doute ensuite ouvrir le "Task Manager" plutôt que d'utiliser la commande "ps".

Oracle permet-il le "retour vers le futur"?

A en croire la section "SQL Language Reference - What's New" d'Oracle 11.1.0.6, ça pourrait être le cas... Je cite la section qui m'intéresse :
"CREATE RESTORE POINT has new syntax that lets you create a restore point for a specified datetime or SCN in the future, and to preserve a flashback database."
Malheureusement la suite semble dire le contraire :
"If you specify TIMESTAMP, then expr must be a valid datetime expression resolving to a time in the past. If you specify SCN, then expr must be a valid SCN in the database in the past."
Et mes tests également (Il est très probable que ce ne soit pas la syntaxe dont ils parlent de toutes façons) :
create restore point gark
as of timestamp
to_timestamp('20/09/2007','DD/MM/YYYY');

create restore point gark
*
ERROR at line 1:
ORA-38743: Time/SCN is in the future of the database.
Je pourrais sans doute faire de l'esprit ici mais ça ne fait rigoler personne donc voici plutôt une question :
  • Qu'est-ce que je rate ?

17 septembre 2007

RAC et ASM 11g sur Linux en pratique (Enfin !)

You can access the content of this post in English here

Après des semaines sans pouvoir y consacrer le temps que j'aurais voulu, ça y est enfin ! J'ai installé aujourd'hui RAC sur Oracle EL5 et rien de spécial à signaler !

La seule difficulté que j'ai rencontrée n'a pas de lien direct avec l'installation ; pour que les droits des devices soient positionnés au démarrage de Oracle EL5 ou RHEL5, il faut creer un fichier dans /etc/udev/rules.d mais j'en ai déjà parlé dans mon post précédent au sujet des raw devices

A part ça, tout est aussi simple qu'en 10g et une fois les pré-requis validés ; en 1H30, c'est bouclé, pour 2 noeuds au moins ; Côté nouveautés, je n'ai rien vu de révolutionnaire mais quand même quelques points utiles ; J'explique !

Point #1 : pas besoin de lancer VIPCA manuellement si votre réseau public est sur une classe d'adresses réservées. Ça c'est quand même confortable parce que mine de rien dans 80% des cas, les réseaux Oracle sont en 192.168.x.x ou 10.x.x.x ! Ils ont même corrigés le Cluster Verify Utility qui n'affiche plus une erreur mais simplement un avertissement quand ça arrive :
Interfaces found on subnet "192.168.245.0" that are likely
candidates for a private interconnect:
sacha eth1:192.168.245.2

WARNING:
Could not find a suitable set of interfaces for VIPs.
Remarquez qu'en revanche il faut toujours une GATEWAY pingable sur l'adresse publique et que le CVU ne semble pas le valider. La punition sinon, c'est que votre VIP ne démarrera pas.

Point #2 : plus besoin d'aucun RAW DEVICES. Les OCR et Voting Disks peuvent être directement dans les partitions (C'est même la configuration désormais recommandée !) ; j'en avais parlé. Il en est de même pour les disques ASM ! Il suffit de changer la chaîne de découverte par "/dev/sdb*" par exemple et vous pouvez ajouter vos devices mode bloc directement sans ASM avec DBCA

Point #3 : Il existe une commande pour vérifier l'état de tous les noeuds du cluster
./crsctl check cluster
sacha ONLINE
kilian ONLINE
Point #4 : Il existe une commande pour faire une sauvegarde manuelle de l'OCR . Ca va etre pratique avant d'ajouter un noeud dans le cluster :
./ocrconfig -manualbackup

sacha 2007/09/16 08:09:13
/u01/crs/cdata/arkz/backup_20070916_080913.ocr

./ocrconfig -showbackup manual

sacha 2007/09/16 08:09:13
/u01/crs/cdata/arkz/backup_20070916_080913.ocr
Point #5 : OPROCD remplace hangcheck-timer. J'en avais parlé ; c'est vérifié !
ps -ef |grep oproc
root 5580 4625 0 07:38 ? 00:00:00 /bin/sh/etc/init.d/init.cssd oprocd
root 6142 5580 0 07:38 ? 00:00:00 /u01/crs/bin/oprocd run -t 1000 -m 500

lsmod |grep hangcheck
Point #6 : ASMCMD offre désormais la commande "cp". Ça permet d'en faire n'importe quoi comme ci-dessous (mes instances fonctionnent) et ça marche
. oraenv
ORACLE_SID = [oracle] ? +ASM1
The Oracle base for ORACLE_HOME=/u01/app/oracle/product/11.1.0/db_1 is /u01/app/oracle

asmcmd
ASMCMD> cd DATA/ORCL/CONTROLFILE

ASMCMD> pwd
+DATA/ORCL/CONTROLFILE

ASMCMD> cp Current.260.633428899 +DATA/ORCL/CONTROLFILE/gark.ctl
source +DATA/ORCL/CONTROLFILE/Current.260.633428899
target +DATA/ORCL/CONTROLFILE/Gark.ctl
copying file(s)...
file, +DATA/orcl/controlfile/gark.ctl, copy committed.

ASMCMD> ls
Current.260.633428899
gark.ctl
Point #7 : La commande lsdsk permet de voir les disques associés à ASM. Par exemple avec l'option -d, cette commande permet de voir les disques associés à un DiskGroup :
. oraenv
ORACLE_SID = [oracle] ? +ASM1
The Oracle base for ORACLE_HOME=/u01/app/oracle/product/11.1.0/db_1 is /u01/app/oracle

asmcmd
ASMCMD> lsdsk -k -d DATA
Total_MB Free_MB OS_MB Name Failgroup Path
1529 864 1529 DATA_0000 DATA_0000 /dev/sdb5
2337 1306 2337 DATA_0001 DATA_0001 /dev/sdb7
Quelques remarques :
  • Il est possible de lancer ASMCMD lorsque ASM est arrêté ; Le message suivant "ASMCMD-08103: failed to connect to ASM; ASMCMD running in non-connected mode" indique que vous allez travailler directement sur les entêtes de disques
  • Pour une raison que j'imagine liée au fait que dans mon cas le paramètre suivant n'a pas la valeur par défaut : asm_diskstring='/dev/sdb*' , lsdsk ne semble pas fonctionner en mode non-connecté
  • Les nouvelles commandes de ASMCMD semblent très intéressantes et notamment md_backup, md_restore et remap. Merci de vos remarques ou commentaires ; c'est trop pour aujourd'hui !
Point #8 : Il est possible d'ajouter et de retirer des Voting Disks alors que le cluster fonctionne. Commençons par l'OCR qui marchait déjà me semble-t-il. Sous l'utilisateur root, vous pouvez ajoutez et supprimer un OCR Mirroir pendant que le clusterware fonctionne comme ceci :
cd /u01/crs/bin

./ocrcheck
Status of Oracle Cluster Registry is as follows :
Version : 2
Total space (kbytes) : 248724
Used space (kbytes) : 2252
Available space (kbytes) : 246472
ID : 433771587
Device/File Name : /dev/sdb8
Device/File integrity check succeeded

Device/File not configured

Cluster registry integrity check succeeded

./ocrconfig -replace ocrmirror /dev/sdb9

./ocrcheck
Status of Oracle Cluster Registry is as follows :
Version : 2
Total space (kbytes) : 248724
Used space (kbytes) : 2252
Available space (kbytes) : 246472
ID : 433771587
Device/File Name : /dev/sdb8
Device/File integrity check succeeded
Device/File Name : /dev/sdb9
Device/File integrity check succeeded

Cluster registry integrity check succeeded

./ocrconfig -replace ocrmirror

./ocrcheck
Status of Oracle Cluster Registry is as follows :
Version : 2
Total space (kbytes) : 248724
Used space (kbytes) : 2252
Available space (kbytes) : 246472
ID : 433771587
Device/File Name : /dev/sdb8
Device/File integrity check succeeded

Device/File not configured

Cluster registry integrity check succeeded
Vous pouvez faire de même avec le Voting Disk alors que le clusterware fonctionne :
dd if=/dev/sdb10 of=/u01/crs/cdata/arkz/voting.copy bs=4k
62244+0 records in
62244+0 records out
254951424 bytes (255 MB) copied, 10.0618 seconds, 24.2 MB/s

./crsctl query css votedisk
0. 0 /dev/sdb10
Located 1 voting disk(s).

./crsctl add css votedisk /dev/sdb11
Successful addition of voting disk /dev/sdb11.

./crsctl add css votedisk /dev/sdb12
Successful addition of voting disk /dev/sdb12.

./crsctl query css votedisk
0. 0 /dev/sdb10
1. 0 /dev/sdb11
2. 0 /dev/sdb12
Located 3 voting disk(s).

# A première vue, il n'est pas possible ensuite de
# supprimer le Voting Disk numero 1 :
./crsctl delete css votedisk /dev/sdb10
Failure 8 with Cluster Synchronization Services while deleting voting disk.

# Dommage ! Mais on peut bien supprimer les autres
# Voting Disk et logiquement un probleme sur le Voting
# Disk 1 ne devrait par impacter le cluster
# re-Dommage, impossible de tester avec ma configuration
./crsctl delete css votedisk /dev/sdb11
Successful deletion of voting disk /dev/sdb11.

./crsctl delete css votedisk /dev/sdb12
Successful deletion of voting disk /dev/sdb12.

./crsctl query css votedisk
0. 0 /dev/sdb10
Located 1 voting disk(s).
Point #9 : On peut tuer des sessions clusterwide. Mince j'ai fait une gaffe dans mon précédent post à ce sujet ! il faut mettre le signe @ avant le numéro d'instance ; ça marche probablement bien en single instance (?)
# Session 1
sqlplus / as sysdba

grant select
on gv_$session
to scott;

# Session 2
sqlplus scott/tiger

select sid, serial#, inst_id
from gv$session
where audsid=sys_context('USERENV','SESSIONID');

SID SERIAL# INST_ID
--- ---------- ----------
67 610 1

# Session 1
alter system
kill session '67, 610, @1'
immediate;

# Session 2
/
select sid, serial#, inst_id
*
ERROR at line 1:
ORA-03135: connection lost contact
Process ID: 29700
Session ID: 67 Serial number: 610
Point #10 : Vous pouvez lancer un script AWR sur tout le RAC au lieu de Instance par Instance. Utilisez spawrrac.sql comme ci-dessous :
@?/rdbms/admin/spawrrac

Instances in this AWR schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Instance
DB Id DB Name Count
----------- ------------ --------
1161209635 ORCL 2

Enter value for dbid: 1161209635
Using 1161209635 for database Id

Specify the number of days of snapshots to choose from
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Entering the number of days (n) will result in the most recent
(n) days of snapshots being listed. Pressing without
specifying a number lists all completed snapshots.

Listing the last 31 days of Completed Snapshots

Snap Instance
DB Name Snap Id End Interval Time Level Count
------------ --------- ----------------- ----- --------
ORCL 1 16 Sep 2007 10:00 1 2
2 16 Sep 2007 11:00 1 2
3 16 Sep 2007 12:00 1 2

Specify the Begin and End Snapshot Ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter value for begin_snap: 1
Begin Snapshot Id specified: 1

Enter value for end_snap: 2
End Snapshot Id specified: 2

Specify the Report Name
~~~~~~~~~~~~~~~~~~~~~~~
The default report file name is spawrrac_1_2. To use this name,
press to continue, otherwise enter an alternative.

Enter value for report_name:

[...]

End of Report ( spawrrac_1_2.lst )

16 septembre 2007

Rapports AWR sur 10 noeuds RAC 10g

J'imagine que ce script ne servira pas à tout le monde mais, si vous avez un RAC 10 noeuds et si vous avez les licences diagnostic pack, voici comment générer les 10 rapports AWR d'un coup ! Sinon, vous n'aurez pas de problème à l'adapter à bos besoins.

Etape 1 : Créer un snapshot
sqlplus / as sysdba

exec dbms_workload_repository.create_snapshot

exit;
Etape 2 : Lister les snapshots

Vous pouvez ensuite lister les snapshots avec le script ci-dessous :
sqlplus / as sysdba

alter session set nls_date_format='DD/MM/YYYY HH24:MI:SS';
col begin_interval_time format a22

accept listdays prompt "Enter number of days you want to query the snapshots (e.g. 1) : "

select s.dbid, s.snap_id,
to_char(s.begin_interval_time,
'DD/MM/YYYY HH24:MI') begin_interval_time
from dba_hist_snapshot s,
v$database d,
v$instance i
where s.dbid=d.dbid
and i.instance_number=s.instance_number
and begin_interval_time>=
(sysdate- &&listdays)
order by snap_id;

exit;
Etape 3 : générer les 10 rapports

Enfin, le script ci-dessous génère tous les rapports AWR simultanement
for i in 1 2 3 4 5 6 7 8 9 10; do
sqlplus /nolog <<EOF
connect /as sysdba
@?/rdbms/admin/awrrpti
text
652855321
$i
1
9094
9096

exit
EOF
done
Remplacez les 3 valeurs en rouge successivement par :
  • Le DBID de la base de données
  • Le snapshot de début de vos rapports
  • Le snapshot de fin de vos rapports
Etape 4 : une autre requête

Une autre requête utile si vous avez des serveurs d'applications devant votre base de données (Okay, c'est du basique mais ça n'empêche pas de s'en servir), ne serait-ce que pour voir se les connexions sont bien équilibrées entre les nœuds de votre cluster :
sqlplus / as sysdba

select inst_id, count(*)
from gv$session
where username is not null
group by inst_id
order by inst_id;

Oracle11g sur Linux : La fin des raw devices ?

D'après la section qui explique la configuration du stockage pour le clusterware dans le document 2 Day RAC 11g, le clusterware n'a pas besoin de Raw Devices à partir de 10.2 sur Redhat 4.0 ; au moins pour le Voting Disk et l'OCR. Ça tombe bien puisque j'installe RAC 11g sur Oracle EL 5.

Petit problème quand même, le répertoire /etc/udev/permissions.d cité dans le document n'existe et ne fonctionne plus avec OEL5 et RHEL5 ! Pour positionnez les droits sur vos partitions, créez un fichier 99-oracle.rules dans le répertoire /etc/udev/rules.d et positionnez les droits comme ci-dessous :
cd /etc/udev/rules.d/
cat 99-oracle.rules
# Oracle Configuration Registry
KERNEL=="sdb[8-9]", OWNER="root", GROUP="oinstall", MODE="640"
# Voting Disks
KERNEL=="sdb1[0-2]", OWNER="oracle", GROUP="oinstall", MODE="640"
# ASM Devices
KERNEL=="sdb[5-7]", OWNER="oracle", GROUP="dba", MODE="660"

Après reboot ;
Si vous voulez l'éviter, utiliser chown et chmod...

ls -l /dev/sdb*
brw-r----- 1 root disk 8, 16 Sep 16 05:45 /dev/sdb
brw-r----- 1 root disk 8, 17 Sep 16 05:45 /dev/sdb1
brw-r----- 1 oracle oinstall 8, 26 Sep 16 05:45 /dev/sdb10
brw-r----- 1 oracle oinstall 8, 27 Sep 16 05:45 /dev/sdb11
brw-r----- 1 oracle oinstall 8, 28 Sep 16 05:45 /dev/sdb12
brw-r----- 1 root disk 8, 29 Sep 16 05:45 /dev/sdb13
brw-rw---- 1 oracle dba 8, 21 Sep 16 05:45 /dev/sdb5
brw-rw---- 1 oracle dba 8, 22 Sep 16 05:45 /dev/sdb6
brw-rw---- 1 oracle dba 8, 23 Sep 16 05:45 /dev/sdb7
brw-r----- 1 root oinstall 8, 24 Sep 16 05:45 /dev/sdb8
brw-r----- 1 root oinstall 8, 25 Sep 16 05:45 /dev/sdb9
Dans l'exemple qui précède,
  • /dev/sdb8 et /dev/sdb9 sont pour l'OCR
  • /dev/sdb10, /dev/sdb11 et /dev/sdb13 sont pour le voting disk
  • /dev/sdb5, /dev/sdb6 et /dev/sdb7 sont pour les disques ASM
Une dernière remarque, si vous voulez malgré tout toujours utiliser des raw devices, avec Oracle EL5 et RHEL5, le fichier /etc/sysconfig/rawdevices n'est plus utilisé. Pour plus d'informations quant à la manière de créer un Raw Device, reportez-vous au Release Notes de Redhat 5 qui en outre propose une syntaxe pour migrer l'ancien fichier dans le nouveau format de description.

Reste à savoir si ASM peut également prendre les devices en mode blocsans ASMLib. Ça sera le cas dans quelques heures normalement !

15 septembre 2007

Hangcheck-Timer est mort, longue vie à OPROCD

Le clusterware Oracle 11g n'utilise plus le module hangcheck-timer sous Linux. A la place Oracle utilise comme sur Unix et Windows, OPROCD. L'implémentation est très différente dans ces 2 cas !

Je dois dire que j'accueille avec un certain plaisir cet fin tragique. Non pas que ce soit compliqué ni que je ne comprenne pas l'utilité de ce module ou même l'intérêt de ne pas parler de ce genre de chose. Comme dit Kirk McGowan, ça marche et le reste, on s'en b.... Bref, un post pour rien ? Comme d'hab !

J'attire juste votre attention sur 2 points :
  • Avez-vous jamais réussi à déclencher le hangcheck-timer ? Moi non. Et pourtant, j'ai fait des tas de trucs pas très catholiques avec le clusterware. Si vous arrivez à déclencher ce module ; je suis plus qu'intéressé par votre test case !
  • Avez-vous remarqué que la documentation d'installation du clusterware sous Linux et la FAQ RAC de Metalink se contredisent sur le sujet du paramétrage du "hangcheck-timer" en 10g. Je me suis laissé dire que la doc avait tord ce qui donnerait sûrement 90% de hangcheck-timer des clusterware sous Linux configurés de manière sous-optimale. Entre nous, vu le point précédent, on s'en fiche un peu (quoique ?).
Pour conclure, nous retiendrons simplement que l'algorithme "Shoot The (Self) Node in The Head" a changé, n'en doutons pas, pour le meilleur !

Enregistrer des services dans le clusterware avec DBCA

Avec 11g, c'est fini et c'est tant mieux ! Vous utiliserez désormais uniquement "srcvtl add service" ou "Oracle Enterprise Manager".

Upload et download depuis vos serveurs Oracle

Juste un mot pour dire qu'il est possible d'uploader directement plusieurs centaines de Mega-Octets de fichiers associés à une SR sur Metalink grace à FTP (Cf note 77483.1). Ça ne vous interdit pas de nettoyer ou d'archiver régulièrement les vieux logs et traces.

D'autre part, il existe une méthode pour télécharger les distributions sur OTN depuis votre serveur avec wget (cf ici) ; C'est encore plus simple si vous utilisez Lynx plutôt que Mozilla ! Et surtout ça permet d'éviter de transporter 200 cookies ; Remarquez que Lynx est surtout utilisable avec Linux.

Enfin, la méthode ci-dessus fonctionne aussi avec les patchs sur Metalink mais à condition d'avoir la bonne URL... Pour cela copiez dans un éditeur de texte l'URL de download du patch et modifiez les valeurs de l'URL ci-dessous pour qu'elles corresponde à votre patch :
http://updates.oracle.com/ARULink
/Download/process_form/XXXX?aru=YYYY&file_id=ZZZZ
où :
  • XXXX est le non du patch (e.g. p5337014_10203_Linux-x86-64.zip)
  • YYYY est numéro aru du patch
  • ZZZZ est l'identifiant du fichier
Voilà avec ces 3 trucs : C'est fini les galères pour échanger les fichiers Oracle à travers toutes les machines de rebond et les VPN ! Quoique... Je ne sais pas comment utiliser FTP avec un proxy

Et créez un référentiel avec vos distributions et patchs ; vous gagnerez du temps !

Plusieurs manières de ne pas démarrer le clusterware ou RAC avec vos serveurs

En 10.2, au moins pour empêcher le démarrage du cluster Oracle sur un serveur :
  • Si vous pouvez, avant d'arrêter votre serveur, connectez-vous root et utilisez la commande "./crsctl disable crs" depuis $ORA_CRS_HOME
  • Sinon, après avoir arrêté votre serveur, avec RHEL ou Oracle EL au moins, démarrez votre serveur et démarrez le en Single-User mode :
    • Connectez-vous à la console lors du démarrage
    • Appuyez sur une touche pour sélectionnez manuellement le menu de démarrage
    • Sélectionnez la version qui vous intéresse au moyen des touches flèche-haut et flèche bas
    • Appuyez sur la touche "e" pour éditer la séquence de démarrage de linux
    • Sélectionnez la seconde ligne de la séquence de démarrage (Celle qui commence par "kernel"...) au moyen des touches flèche-haut et flèche-bas
    • Appuyez sur la touche "e" pour éditer cette ligne
    • Ajoutez un espace la lettre S à la fin de la ligne ou si vous préférez, le mot "Single". Et appuyer sur la touche "Enter", "Entrée" ou "Return" pour valider la modification
    • Appuyer sur la touche "b" pour démarrer Linux. Le mode Single-User sera activé.
    • Une fois que c'est fait, vous pouvez désactivez le clusterware en utilisant la commande "./crsctl disable crs" depuis $ORA_CRS_HOME puis démarrer dans le level de votre choix (e.g level 5 avec la commande "init 5")
Remarque :
Cette seconde méthode vous permet également de modifier le mot de passe root si vous l'avez oublié ou en modifiant la ligne "id:5:initdefault:" du fichier /etc/inittab et en remplaçant le 5 par une autre valeur, de démarrer dans le level que vous voulez automatiquement. Il faut noter que le clusterware démarre dans les level 3 et 5 !

D'autre part, il est également possible de démarrer automatiquement le clusterware mais de demander le démarrage manuel de la base de données. On agit lors sur le démarrage de toutes les instances - même en 11.1, il n'est pas possible de passer une instance uniquement en mode de démarrage manuel sans bidouiller la ressources avec les commandes crs_xxx ce qui n'est bien sur pas supporté; pour se faire, connectez-vous Oracle et utilisez la ligne de commande qui suit :
srvctl modify database \
-d <database name> \
-y manual
La ligne de commande suivante effectue quant à elle l'opération inverse :
srvctl modify database \
-d <database name> \
-y automatic

DBMS_FGA : triggers sur SELECTs ?

Ce message ne sera pas long ; je suis déçu ! Celui ou celle qui vous a laissé miroiter que DBMS_FGA permet de créer des triggers sur des SELECT avait tord, intentionnellement ou non. Le pire, c'est que je fais parti de ceux qui l'on cru. Je m'explique...

Voici comment mettre en œuvre un exemple simple avec DBMS_FGA pour traquer les programmes qui font des SELECT ou des ordres DML sur une table DEMO.

Étape 1 : Un schéma exemple

Pour les besoins de l'exemple, créez un schéma DEMO et une table DEMO comme ci-dessous :
sqlplus / as sysdba

create user demo
identified by demo
default tablespace users
temporary tablespace temp;

grant connect, resource to demo;

grant select on v_$session to demo;

connect demo/demo

create table demo(id number);

exit;
Étape 2 : Une table pour traquer les SELECT et une procédure pour l'alimenter

Pour les besoins de l'exemple on va créer une table AUDIT_DEMO qui contiendra l'heure, ainsi que le programme qui accède à la table DEMO. Remarquez que je fais exprès de choisit le PROGRAM puisque ce n'est pas une information qui est traquée dans la table d'audit du système et qu'il faut donc écrire du code pour capturer cette information.
sqlplus / as sysdba

create table demo.audit_demo (
sdate date,
otype number,
program varchar2(50));
Maintenant nous allons créer un package PL/SQL qui va retrouver les informations de la session comme le type de l'ordre ou le PROGRAM associée. Comme ce package devra s'exécuter à l'extérieur de la transaction en cours, nous alons positionner le "PRAGMA AUTONOMOUS_TRANSACTION" comme ci-dessous :

create or replace package demo.demo_fga_handler is
PROCEDURE track_demo_access( object_schema VARCHAR2,
object_name VARCHAR2,
policy_name VARCHAR2 );
end;
/
show errors

create or replace package body demo.demo_fga_handler as
PROCEDURE track_demo_access( object_schema VARCHAR2,
object_name VARCHAR2,
policy_name VARCHAR2 )
is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into audit_demo(sdate, otype, program)
(select sysdate, command, substr(program,1,50)
from v$session
where audsid=sys_context('USERENV','SESSIONID')
and sid=sys_context('USERENV','SID'));
commit;
end track_demo_access;
end;
/
show errors
Étape 3 : Créer un POLICY DBMS_FGA qui déclenche la procédure sur un select ou un ordre DML à la table DEMO

Maintenant, il suffit de créer une policy qui permette de déclencher le package dès qu'un ordre select ou dml est exécuté :
BEGIN
DBMS_FGA.ADD_POLICY(
object_schema => 'DEMO',
object_name => 'DEMO',
policy_name => 'TRACK_DEMO_DEMO',
handler_schema => 'DEMO',
handler_module => 'demo.demo_fga_handler.'||
'track_demo_access',
enable => true,
statement_types => 'SELECT, INSERT, UPDATE, DELETE',
audit_trail => DBMS_FGA.DB);
END;
/
Étape 4 : Tester

Un test simple montre bien que la procédure fonctionne comme attendue (Attention ca ne marche pas si vous êtes connecté SYSDBA en 10.2.0.1 et 10.2.0.2 ;) ). Remarquez que c'est vrai même si la transaction est annulée par un ROLLBACK;
connect demo/demo

alter session set nls_date_format='DD/MM/YYYY HH24:MI:SS';

insert into demo values(1);

update demo set id=2 where id=1;

delete from demo where id=1;

select * from demo;

select otype, sdate, program
from audit_demo;

OTYPE SDATE PROGRAM
----- ------------------- -------
2 13/09/2007 13:43:49 sqlplus
6 13/09/2007 13:43:49 sqlplus
7 13/09/2007 13:43:49 sqlplus
3 13/09/2007 13:43:49 sqlplus

ROLLBACK;

select otype, sdate, program
from audit_demo;

OTYPE SDATE PROGRAM
----- ------------------- -------
2 13/09/2007 13:43:49 sqlplus
6 13/09/2007 13:43:49 sqlplus
7 13/09/2007 13:43:49 sqlplus
3 13/09/2007 13:43:49 sqlplus
Étape 5 : Où es le problème ?

Peut-être n'y a-t-il pas de problème mais moi, j'en ai un ! En plus du trigger, les informations d'audit sont journalisées dans la table SYS.FGA_LOG$ ou, éventuellement, dans un fichier XML. Et mon problème, c'est moins l'espace (On peut toujours faire regulièrement un "delete from SYS.FGA_LOG$") que l'impact sur les performances de cette opération. Il y a 2 index système sur cette table ; Sur ma base de données, j'ai évalué à 2 ms par appel, l'impact de cette journalisation avec un debit de 500 appels par secondes et je ne vous dirai pas le pire ! Ce qui est "funny", c'est que écrire dans un fichier XML est plus efficace dans le cas de ma configuration

Voilà, je n'ai pas trouvé de moyen de désactiver cette journalisation ; regardez les valeurs possible du parametre audit_trail de la procedure DBMS_FGA.ADD_POLICY ! Bref, si vous voulez utiliser DBMS_FGA, c'est simple et très efficace mais il y a certaines limites à pas franchir et on dirait que c'est ce que j'ai essayé de faire ! Heureusement, je m'en suis rendu compte lors de mes tests de charge.

Étape 6 : Nettoyer

Comme d'hab...
sqlplus / as sysdba

drop user demo cascade;

Database Resident Connection Pooling (DRCP)

DRCP est la meilleure raison que j'ai trouvée jusqu'à présent pour migrer en 11g dès que possible. Bien sur, si vous utilisez une application qui établit beaucoup de connexions de courte durée, comme c'est généralement le cas avec une application web écrite en Perl ou PHP ; c'est redoutable pour ce problème !

Jusqu'en 10g, l'équation "beaucoup de connexions = beaucoup de problèmes" est souvent vrai et si vous avez mis en oeuvre Shared Server (aka MTS), vous savez de quoi on parle ici. 11g promet d'adresser nos préoccupations et les problèmes de connexions de nos applications Perl ou PHP, grâce (traduit littéralement) au pooling de connexions qui réside dans la base de données. Remarquez qu'on parle de base de données et pas d'instance ; ça doit être compatible avec RAC !

Étape 1 - Démarrer un Pool DRCP

Ça commence par une bonne nouvelle, c'est effectivement très simple à mettre en œuvre. Le package PL/SQL DBMS_CONNECTION_POOL a 5 procédures qui sont :
  • CONFIGURE_POOL
  • START_POOL
  • STOP_POOL
  • ALTER_PARAM
  • RESTORE_DEFAULTS
Je vous renvoie aux sections associées dans Oracle 11g Administrator's Guide et Oracle 11g PL/SQL Packages and Types Reference et pour ce qui est de la signification et des paramètres de ces procédures. A utiliser, c'est assez simple surtout si vous vous appuyez sur le Pool par défaut qui s'appelle SYS_DEFAULT_CONNECTION_POOL. Connectez-vous SYS et démarrer ce pool par défaut
sqlplus / as sysdba
exec DBMS_CONNECTION_POOL.ALTER_PARAM ( -
'SYS_DEFAULT_CONNECTION_POOL','MINSIZE',1);
exec DBMS_CONNECTION_POOL.ALTER_PARAM ( -
'SYS_DEFAULT_CONNECTION_POOL','MAXSIZE',2);
exec DBMS_CONNECTION_POOL.ALTER_PARAM ( -
'SYS_DEFAULT_CONNECTION_POOL','INCRSIZE',1);
exec dbms_connection_pool.start_pool
Une fois le pool démarré, vous devez voir apparaître des process particulier (CMON) s'enregistrer dans le listener comme ci-dessous :
lsnrctl service
[...]
Service "ORCL" has 1 instance(s).
Instance "ORCL", status READY, has 2 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
LOCAL SERVER
"N000" established:0 refused:0 current:0 max:679 state:ready
CMON
(ADDRESS=(PROTOCOL=tcp)(HOST=arkzoyd)(PORT=63118))
Étape 2- Se connecter via le pool

Pas beaucoup plus compliqué, ajoutez la section "(SERVER=POOLED)" dans la description de votre alias TNS. Par exemple, mon alias TNS version la base qui sert le service "orcl" est le suivant :
ORCL_POOLED=(DESCRIPTION=
(ADDRESS=
(PROTOCOL=tcp)
(HOST=localhost)
(PORT=1521)
)
(CONNECT_DATA=
(SERVICE_NAME=orcl)
(SERVER=POOLED)
)
)
Vous pouvez également utiliser Network Manager (netmgr) pour configurer votre connexion, Sélectionnez "Pooled Server" comme type de connexion.


Pour vous connecter, rien ne change ce qui est plutôt une bonne nouvelle si vous voulez pouvoir en bénéficier simplement :
sqlplus scott@orcl_pooled
Remarque
Si vous tentez de vous connecter alors que le pool n'est pas démarrer, vous devez recevoir l'erreur suivante :
ORA-12520: TNS:listener could not find
available handler for requested type of server
Étape 3 : "Démontrer" que le Pool fonctionne bien

Bien sur le test qui suit est très loin d'apporter une démonstration irréfutable mais c'est un début et sur mon portable, le résultat est un bon début; Commencez par créer un script qui lance 20 connexions les unes après les autres.
#!/bin/bash
i=$1
sqlplus /nolog <<EOF
!date
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
connect scott/tiger@$i
!date
exit;
EOF
Une fois le script écrit, lancez-le successivement avec une connexion qui utilise le Pool et une connexion dédiée. Comparez :
chmod +x tst.sh
tst.sh orcl_pooled
txt.sh orcl
Ce test simple affiche des résultats sont du simple au double (3 secondes dans le cas du DRCP contre 6 secondes sans) alors imaginez avec une vrai charge et des dizaines de connexions qui arrivent simultanément...

Étape 4 : Superviser les Pools de connexions

La requête suivante vous donne la configuration de vos pools DRCP :
set head off
select '----------------------------------------------- ' BEGIN,
'CONNECTION_POOL : '||CONNECTION_POOL CONNECTION_POOL,
'STATUS : '||STATUS STATUS,
'MINSIZE : '||to_char(MINSIZE) MINSIZE,
'MAXSIZE : '||to_char(MAXSIZE) MAXSIZE,
'INCRSIZE : '||to_char(INCRSIZE) INCRSIZE,
'SESSION_CACHED_CURSORS : '||
to_char(SESSION_CACHED_CURSORS) SESSION_CACHED_CURSORS,
'INACTIVITY_TIMEOUT : '||
to_char(INACTIVITY_TIMEOUT) INACTIVITY_TIMEOUT,
'MAX_THINK_TIME : '||
to_char(MAX_THINK_TIME) MAX_THINK_TIME,
'MAX_USE_SESSION : '||
to_char(MAX_USE_SESSION) MAX_USE_SESSION,
'MAX_LIFETIME_SESSION : '||
to_char(MAX_LIFETIME_SESSION) MAX_LIFETIME_SESSION,
'----------------------------------------------- ' END
from DBA_CPOOL_INFO;
set head on

-----------------------------------------------
CONNECTION_POOL : SYS_DEFAULT_CONNECTION_POOL
STATUS : ACTIVE
MINSIZE : 1
MAXSIZE : 2
INCRSIZE : 1
SESSION_CACHED_CURSORS : 20
INACTIVITY_TIMEOUT : 300
MAX_THINK_TIME : 30
MAX_USE_SESSION : 500000
MAX_LIFETIME_SESSION : 86400
-----------------------------------------------
Celle-ci donne les statistiques associées :
set head off
select '----------------------------------------------- ' BEGIN,
'POOL_NAME : '||POOL_NAME POOL_NAME,
'NUM_OPEN_SERVERS : '||
to_char(NUM_OPEN_SERVERS) NUM_OPEN_SERVERS,
'NUM_BUSY_SERVERS : '||
to_char(NUM_BUSY_SERVERS) NUM_BUSY_SERVERS,
'NUM_AUTH_SERVERS : '||
to_char(NUM_AUTH_SERVERS) NUM_AUTH_SERVERS,
'NUM_HITS : '||to_char(NUM_HITS) NUM_HITS,
'NUM_MISSES : '||to_char(NUM_MISSES) NUM_MISSES,
'NUM_WAITS : '||to_char(NUM_WAITS) NUM_WAITS,
'WAIT_TIME : '||to_char(WAIT_TIME) WAIT_TIME,
'CLIENT_REQ_TIMEOUTS : '||
to_char(CLIENT_REQ_TIMEOUTS) CLIENT_REQ_TIMEOUTS,
'NUM_AUTHENTICATIONS : '||
to_char(NUM_AUTHENTICATIONS) NUM_AUTHENTICATIONS,
'NUM_PURGED : '||to_char(NUM_PURGED) NUM_PURGED,
'HISTORIC_MAX : '||to_char(HISTORIC_MAX) HISTORIC_MAX,
'----------------------------------------------- ' END
from V$CPOOL_STATS;
set head on

---------------------------------------
POOL_NAME : SYS_DEFAULT_CONNECTION_POOL
NUM_OPEN_SERVERS : 1
NUM_BUSY_SERVERS : 0
NUM_AUTH_SERVERS : 1
NUM_HITS : 0
NUM_MISSES : 2
NUM_WAITS : 1
WAIT_TIME : 0
CLIENT_REQ_TIMEOUTS : 0
NUM_AUTHENTICATIONS : 3
NUM_PURGED : 0
HISTORIC_MAX : 1
---------------------------------------
La requête qui suit décompose l'utilisation du Pool de connections par classe d'utilisation :
set head off
select '----------------------------------------------- ' BEGIN,
'CCLASS_NAME : '||CCLASS_NAME CCLASS_NAME,
'NUM_REQUESTS : '||to_char(NUM_REQUESTS) NUM_REQUESTS,
'NUM_HITS : '||to_char(NUM_HITS) NUM_HITS,
'NUM_MISSES : '||to_char(NUM_MISSES) NUM_MISSES,
'NUM_WAITS : '||to_char(NUM_WAITS) NUM_WAITS,
'WAIT_TIME : '||to_char(WAIT_TIME) WAIT_TIME,
'CLIENT_REQ_TIMEOUTS : '||
to_char(CLIENT_REQ_TIMEOUTS) CLIENT_REQ_TIMEOUTS,
'NUM_AUTHENTICATIONS : '||
to_char(NUM_AUTHENTICATIONS) NUM_AUTHENTICATIONS,
'----------------------------------------------- ' END
from V$CPOOL_CC_STATS;
set head on

-----------------------------------------------
CCLASS_NAME : SCOTT.SHARED
NUM_REQUESTS : 2
NUM_HITS : 0
NUM_MISSES : 2
NUM_WAITS : 1
WAIT_TIME : 0
CLIENT_REQ_TIMEOUTS : 0
NUM_AUTHENTICATIONS : 3
-----------------------------------------------
Étape 5 : Aller plus loin avec un second test

Un test supplémentaire permet de mettre en évidence de manière différente le fonctionnement de DRCP. Ouvrez deux sessions
>> Session 1
sqlplus scott/tiger@orcl_pooled
select * from dual

>> Session 2
sqlplus / as sysdba
select s.sid,
s.serial#,
s.audsid,
s.server,
p.spid,
p.pid
from v$session s, v$process p
where s.username='SCOTT'
and s.spid=s.process;

SID SERIAL# AUDSID SERVER SPID PID
--- ------- ------ --------- ---- ---
133 259 190128 DEDICATED 2868 27

!ps -ef |grep 2868

oracle 2868 1 0 22:42 ? 00:00:00 ora_l001_ORCL
Vous constaterez donc que la session est marquée "DEDICATED" mais que le process n'est pas un process serveur classique, c'est un process lnnn. Si vous déconnectez la session SCOTT, le process reste présent (le minimum est 1 dans mon cas). Si vous reconnectez une nouvelle session au DRCP, voici un exemple de comment V$SESSION évolue :
select s.sid,
s.serial#,
s.audsid,
s.server,
p.spid,
p.pid
from v$session s, v$process p
where s.username='SCOTT'
and s.spid=s.process;

SID SERIAL# AUDSID SERVER SPID PID
--- ------- ------ --------- ---- ---
133 263 190130 DEDICATED 2868 27
Étape 6 : Allez beaucoup plus loin

L'étape d'après, c'est de trouver les "events" associées à cette nouvelle fonctionnalité et de décortiquer les internes mais (1) ce n'est pas pour tout de suite et (2) ce n'est même pas pour moi mais pour les experts. Vous avez donc du travail messieurs et mesdames ! N'hésitez pas à commenter ce post avec vos retours d'expérience !

Nota Bene :
Si vos connexions restent "Idle" trop longtemps, elles seront déconnectée et avec SQL*Plus, il est très probable que vous expérimentiez des ORA-3113. Regardez le paramètre "inactivity_timeout" de votre pool.

13 septembre 2007

Migrer systématiquement vers le dernier Patch Set ?

Cette semaine, en fait depuis vendredi dernier 2 heures 54 du matin, j'ai vécu, au travail, la semaine la plus intense depuis des mois ou même des années ! Et quand je dis je, je devrais dire une bonne partie des équipes de The Pythian Group que vous connaissez sûrement et tout ça à cause de l'équipe à laquelle j'appartiens ; pour ne pas dire moi ;)

Avant d'aller plus loin, voici quelques explications sur le groupe ;

Nous sommes une cinquantaine de DBA, essentiellement Oracle, dans une moindre mesure MySQL ou SQL*Server. Nous travaillons depuis le monde entier, c'est à dire Canada, UK, Autralie, Indes et bientôt Roumanie, pour des clients dans le monde entier. ;) J'aime bien Boston et la Californie ! Nous sommes organisés en clusters et chaque équipe de 3 à 5 DBA gère généralement des environnements de base de données de clients d'horizon très divers, la plupart du temps, en soutien à leurs propres DBA, en particulier quand ce sont de grandes sociétés. Pour la petite histoire et pour illustrer l'intérêt d'équipes comme la nôtre, le "cluster" auquel j'appartiens est constitué de 3 personnes situées toutes à Ottawa. Nous gérons, parmi d'autres environnements, celui d'une société située en Indes. C'est, à peu prêt, l'inverse de tout ce qui se fait en ce moment, non ? D'ailleurs, j'aimerais bien avoir un client en France, même pour 16 heures par mois, histoire de montrer aux collègues qu'en France aussi, on fait des trucs intéressants. Si vous avez des idées laissez un commentaire, je ne le publierai pas.

Là je suis à 10,000 km de l'objectif de ce post !

Nous sommes 3 dans l'équipe dans laquelle je travaille et nous gérons, entre autre 7 clusters RAC dont 4 en production et 1 en standby. Nos productions ont respectivement 2, 4 (depuis 5 jours !), 7 et 10 nœuds ; et tous sont en 10.2.0.2 ; nous y arrivons !

La semaine dernière, donc au menu, le démarrage de la saison NFL (un énorme choc pour le cluster 10 noeuds), supprimer et ajouter un nœud au cluster 7 nœuds et passer un cluster de 2 nœuds à 4 nœuds et le résultat (en moins de 7 jours), ça a été :
  • 1 bug qui génère des ORA-600 et fait crasher des connexions
  • 1 bug qui empêche PMON d'informer les listeners comme il faut et le loadbalancing serveur mal fait
  • 1 bug qui bloque les nouvelles sessions, génère des ORA-3135 pour les nouvelles sessions et "crash" une instance
  • 1 bug qui oblige à arrêter le cluster complet pour réactiver les flashback log
  • 1 bug sur le FAL dans le cas de RAC avec un nombre de nœud différents de la standby
  • 1 SR sévérité 1
  • 1 SR sévérité 2 et une sévérité 4
  • 3 crashs d'instances
Et tous les correctifs sont dans 10.2.0.3 ! Alors bien sur, il y a aussi les impondérables que nous n'aurions peut-être pas évité :
  • Plusieurs erreurs dans le design comme celle qu'explique Christo ici.
  • 2 pannes matérielles
Et pourtant (1) nous avions toutes les bonnes préconisations 3 mois mais qui ça intéresse de passer du temps et de l'argent à migrer en 10.2.0.3 ou à modifier des séquences et le code de l'application ? (2) Le support Oracle n'a rejeté aucune de mes SR malgré le niveau de version ; ils sont même en ce moment en train d'étudier la possibilité de back porter un one-off pour une de nos bases de données que pour des raisons indépendantes de notre volonté et de celle du client, on ne peut vraiment pas mettre à jour en 10.2.0.3.

Tout ça est très positif pour moi ; 5,6 jours à récupérer après cette semaine de fou et, avec aucune véritable erreur (On peut toujours être plus rapide ! mais je m'en sors vraiment bien), de nombreux points d'expérience de toutes part. Si cette nuit est comme la dernière on pourra dire qu'on s'en est sorti avec les honneurs...

En même temps, j'ai vraiment des scrupules quand je me dis que tout ça aurait pu être évité ; j'imagine que c'est la dernière fois qu'on laisse traîner un Patch Set aussi longtemps chez ces 2 clients.

Alors voilà, ça ne reste que mon opinion, si vous avez une base de données que vous utilisez jusqu'à certaines limites et sans vous précipiter le lendemain de la sortie du Patch Set... Rester en ligne ne vous fera peut-être pas gagner des millions de dollars mais nous aurait évité bien des ennuis... Qu'est-ce que vous en pensez ?

Au fait, ça y est ; première installation de 11g sur le développement d'un nouveau projet la semaine prochaine. Dommage que ce ne soit pas dans mon cluster. Enfin, on ne peut pas tout avoir !

La liberté ou l'Internet ?

Rester anonyme et vivre sans se sentir épié sur internet est chose complexe... Achetez un livre sur Amazon et il vous proposera sans relâche les livres les plus "pertinents". Allez sur un article qui parle d'Oracle et vous voyez une publicité pour DB2. Lisez un article Yahoo! et la même pub pour DB2 revient ; sans cesse.

Ne pas être matraqué de publicité sur Internet ; un rêve ? C'est d'autant plus flagrant qu'à Ottawa il n'y a pas de grand panneau de pub dans la rue : c'est interdit !

Mais j'y pense : cette pub DB2 n'est vraiment pas pertinente ! Regardez bien mon profil... Ça fait 10 ans que je ne fais que de l'Oracle matin, midi et soir ; même la nuit s'il faut. Quel est le publicitaire qui peut croire qu'une publicité sur Internet va me faire changer pour DB2 ? Je ne dis pas que je ne changerai jamais mais quel est l'intérêt pour IBM de payer ne serait-ce qu'un seul cents dans cette pub ? C'est juste de l'argent jeté par la fenêtre.

En fait, j'aime cette publicité DB2. Pourquoi ? Parce qu'à la fin ce sont les utilisateurs de DB2 qui la paient. Et avec un peu de chance, cette pub contribuera à la faillite de DB2. lol !

Bon mais tout ça est très théorique parce que comme des millions d'utilisateurs de Firefox probablement, j'utilise tous les outils possible pour effacer mes traces et bloquer ce qui peut l'être... mais voici qu'on m'accuse de causer la faillite d'Internet :
  • Si tout le monde, dont je fais parti, bloque les pubs avec Adblock Plus, tous les gens qui ne vivent que de ça comme Google vont mourir et Internet aussi ! Une guerre fait rage avec ses arguments et ses contre-arguments. On a même invente l'anti-anti bloqueur de publicité.
  • Heureusement, j'ai une autre plugin : NoScript qui permet de bloquer finement les Javascripts et ainsi de servir de anti-anti-anti bloqueur de pub et d'eviter les marqueurs créés avec des XSS
  • Bien sur, ces 2 plugins ont beaucoup de cousins. Par exemple TOR a fait parlé d'elle récemment est puisque plusieurs utilisateurs se sont fait hacker leur mots de passe par le biais de sites qui n'utilisent pas SSL pour demander les mots de passe ! J'utilise aussi TOR.
  • Google Mobile et le User Agent Switcher permettent si vous positionnez l'agent sur un Browser Mobile (e.g. IE sur Windows CE) et que vous positionnez les "Settings" de votre compte sur "Format web pages for your phone : On" de ne diminuer les traces que vous laissez sur les sites que vous visitez et même de piéger les contrôles que certaines entreprises mettent en place pour éviter que leurs employés utilisent trop sur Internet.
Voila ! Comme je ne veux pas détruire internet, je réactive tous les panneaux de publicité ce soir. Si en plus ça peut causer la faillite d'IBM et de Microsoft, j'aurais fait une B.A aujourd'hui ; Au moins une fois par jour, je cliquerai sur leur bannière de pub !

le TPC est une mine d'or

Le TPC est une mine d'informations et je ne dis pas ça parce qu'Oracle est souvent leader en performance et/ou en prix en "scotchant" tout le monde ! Quelques exemples :
  • Le fait que Oracle11g soit disponible sous Windows est sans doute une étape importante pour l'adoption de la nouvelle version puisque les premiers tests sont souvent fait sur les postes des DBA et, à mon grand regret, ils ne sont pas encore tous sous Linux (En attendant, si vous ne l'avez pas encore fait, utilisez VMWare Server et Oracle Enterprise Linux) :
    • Oracle sous Windows c'est pour bientôt ! Exécuter un bench sur Windows x86_64, même si c'est du courant pour Oracle indique une bonne maturité du moteur sur 64 bits donc sur 32 surement plus encore
    • Oracle 11g pour Windows x86_64 sera disponible le 31 décembre 2007 (Probabilité 97% comme dirait Gartner) ! en effet, le TPC-C oblige à indiquer une date de disponibilité de la configuration avec le résultat; la spec indique "To be compliant with the TPC-C standard, all references to TPC-C results must include the tpmC rate, the associated price-per-tpmC, and the availability date of the priced configuration."' Et le bench indique le 31 décembre 2007
    • Linux n'apporte rien de spécial aux performances ou au cout d'un système (ou au moins sur un bench TPC-C !) puisque, certes avec 3 mois d'expérience supplémentaire, Oracle 11g Windows x86_64 bat Oracle 11g Linux sur une configuration très comparable. Pour vos choix, ces 2 critères ne sont pas forcément pertinents. Et ça ne m'empêchera pas d'être un fervent défenseur de Linux !
  • Vous pouvez voir les techniques que les "bench marketer" utilisent pour arriver à ces performances extrêmes. Ouvrez le rapport complet de ce benchmark et regardez :
    • Les 2 redo logs font 14 Go
    • Les segments cluster sont utilises de manière intensive
    • Le cache est différencié et la base de données utilise plusieurs tailles de blocks
    • etc, etc, etc... vous pouvez y rester des heures
  • Vous pouvez découvrir des approches étonnantes dans ces tests :
    • Ce bench Panta utilise un lien interconnect RDS sur infiniband
    • Oracle offre une avec RAC sur HP et 16 noeuds une vrai approche de montée en charge horizontale ici alors que Microsoft offre (2 ans plus tard, certes !) avec SQL*Server sur HP Superdome une montée en charge verticale et que la différence de prix se fait parfois en partie sur le niveau de discount du constructeur
    • Sur le seul bench TPC-H 30TB, le ratio entre le volume des données et le volume disque est de 14.96 ; la mémoire est de 1To (1024 Go). Il y a 500 To de disques, non pas dans une super baies XP mais sur 256 baies MSA 1000. Étonnant non, pourquoi ce choix ? Bien sur nous le savons tous.
Bref, je l'ai déjà dit; il faut suivre les benchmarks TPC ; c'est vraiment instructif !

12 septembre 2007

Votre priorité sera traitée pendant les heures de bureau

Je ne suis pas très habitué à de ce genre d'exercices (la chance sans doute !). Alors quand j'ai ouvert ma S1... Quelle surprise de voir qu'elle serait traitée pendant les heures de bureau : Merci seigneur ! Ils m'ont rappelé dans le quart-d'heure : Peut-on ouvrir un bug Metalink sur Metalink ? Je laisse faire les experts ;)