La version détaillée est en anglais sur mon blog à dbi services.
Ici un résumé, laissez un commentaire ici pour plus de détail en français.
Lorsqu’on génère une clé primaire à partir d’une sequence, le problème est que toutes les insertions concurrentes vont toucher au même bloc d’index. Puisque les valeurs venant de la sequence s’incrémentent elles vont toutes à la fin de l’index.
Il est souvent conseillé d’utiliser un index REVERSE pour disperser ces valeurs. Mais ce n’est pas bon non plus car elles seront trop dispersées. Les inserts vont toucher à tous les blocs de l’index et dès qu’il y aura un peu de volume ça ne logera plus en buffer cache.
L’autre conseil est alors de partitioner l’index par HASH. Effectivement, on distribue les inserts sur quelques blocs. Mais en RAC on va voir passer ces blocs d’un noeud à l’autre, et on aura à nouveau des contentions.
Ce qu’il faut, c’est distribuer les inserts non pas en fonction des valeurs générées, mais en fonction de la session. Le but est qu’une session touche au même bloc d’index pour ses inserts, mais qu’une autre session touche à un autre bloc, surtout si elle est sur un autre noeud du RAC. La solution est donc de préfixer le numéro qui vient de la sequence avec un ora_hash() ou un mod() du session_id. Et mettre devant le numéro d’instance si on est en RAC.
La clé sera un peu plus longue, mais c’est toujours mieux qu’un reverse index qui va faire grossir tout l’index. Les numéros ne seront plus consécutifs, mais de toute façon ça n’a jamais été le cas. Une sequence sert à fournir un nombre unique pour une clé générée, pas è numéroter dans l’ordre.
En 12c il y a une option de la sequence qui permet de faire le préfixage automatiquement en donnant simplement le nombre de partition. Mais ce n’est pas documenté… donc à ne pas utiliser. J’espère le voir sur une prochaine version.
La demo est ici.