Configurer sa baie de stockage pour une base de données

Les accès disques sont souvent un goulot d’étranglement pour la base base de données. En l’optimisant, on peut les diminuer mais rarement les éliminer du fait des éléments suivants :

  • malgré la baisse du prix de la mémoire, il est couteux de faire tenir sa base de donnée en entier dans la mémoire ;
  • depuis la 8i, l’algorithme de gestion du tampon de données rend très difficile la persistance des blocks de données dans le tampon lorsqu’ils sont récoltés lors de :
    • un parcours complet de table à taille importante ;
    • un parcours d’intervalle d’index à taille importante ;
  • quand il faut écrire les blocks, les accès disque ne peuvent être outre-passés.

Il m’arrive souvent de découvrir des configurations de baies de stockage vraiment sous-optimales pour des bases de production. C’est pourquoi je vais essayer de répertorier dans cette article les bonnes pratiques sur un domaine qui n’est en général pas de mon ressort mais qui a un fort impact sur mon activité professionnelle : la configuration des baies de stockage.
Tout d’abord un petit test par rapport au tampon de données. La requête que j’utilise pour illustrer mon propos sur l’algorithme de LRU du tampon est la suivante :
[sourcecode language= »sql »]
select * from <ma_table> order by <ma_colonne> ;
[/sourcecode]
<ma_table> a la propriété d’avoir une taille supérieure à 25% du tampon de données et un grand nombre de lignes (> 5 millions).
<ma_colonne> a la propriété d’avoir peu de valeurs distinctes et pas mal null. La clause « order by » permet alors de contourner le « array fetch » de SQL Developer.
Les statistiques sur les attentes sont collectées de la manière suivante :
[sourcecode language= »sql »]
select event,time_waited from v$session_event
where sid=539
and wait_class<>’Idle’
order by time_waited desc;
[/sourcecode]
Les statistiques IO sont collectées de la manière suivante :
[sourcecode language= »sql »]
select value from v$sesstat s
join v$statname n on s.statistic#=n.statistic#
where s.sid=539
and name like ‘physical reads’
order by s.value desc ;
[/sourcecode]
Les valeurs initiales sont les suivantes :
/* attentes */

EVENT TIME_WAITED
db file sequential read 114
db file scattered read 22

/* IOs */

VALUE
181

Après la première exécution de la requête, les résultats sont les suivants :
/* attentes */

EVENT TIME_WAITED
db file sequential read 10873
db file scattered read 115

/* IOs */

VALUE
49347

Après la deuxième exécution de la requête, les résultats sont les suivants :
/* attentes */

EVENT TIME_WAITED
db file sequential read 19051
db file scattered read 118

/* IOs */

VALUE
98495

On peut ainsi voir que sur ce genre de requête, les données ne sont pas mises en tampon mais relues sur le disque. A noter qui si vous êtes en version Enterprise, vous pouvez paralléliser la requête et les attentes se transforment en « direct path read » ce qui améliore les performance en court-circuitant complètement le tampon. Mieux, en 11g, le « direct path read » est utilisé même sans parallélisme.
On comprend ainsi la criticité de bonnes performances au niveau stockage. Et pour revenir à la configuration des baies de stockage, les règles qui me semblent être de bonnes pratiques pour les bases de données de production sont les suivantes :

  • les baies de stockages devraient être conçues en fonction des besoins en performance et non pas en espace disque : la capacité disque a en effet outrageusement augmenté ces dernières années par rapport aux leurs performances et le dimensionnement des volumes par rapport à leur taille peut s’avérer catastrophique ;
  • privilégiez des disques de bonne qualité : au final, c’est le disque qui effectue l’IO, ce n’est pas le contrôleur ; une baie de stockage avec un contrôleur moyen mais de très bons disques fournira de très bonnes performances mais pas l’inverse ;
  • utilisez du RAID 10 : celui-ci n’a pas à gérer de parité ; ainsi, le RAID5 (ou autres types de RAID à base de parité) se retrouve dans l’obligation de lire toutes les blocs de la ligne de RAID afin de pouvoir calculer la parité lors de l’écriture ; les disques étant suffisamment volumineux actuellement, cela ne devrait pas être un problème;
  • les performances d’un volume de stockage en RAID 10 sont proportionnelles au nombre de disques qui sont dans la grappe RAID ; autrement dit, plus vous mettez de disques, plus votre système de stockage sera performant ;
  • ne distribuez pas vos données sur plusieurs LUNs à l’intérieur d’une même grappe RAID, cela entraine des déplacement de tête des disques, qui sont la cause principale des attentes d’un système de stockage ; si par exemple vous utilisez un gestionnaire de volume logique et que vous voulez agrandir le groupe de volume où est stocké la base, il vaut mieux agrandir la LUN dans la grappe RAID puis agrandir le groupe de volumes plutot que de re-créer une LUN supplémentaire dans la grappe RAID et de l’intégrer dans le gestionnaire de volumes logiques ;
  • Segmentez votre baie : ne créez pas une grosse grappe RAID fourre-tout, mais distinguez plutôt vos grappes pour les différentes fonctions de vos serveurs : base de données, NAS, mail, virtualisation.

Pour finir, si vous ne voulez pas vous embêter, vous pouvez utiliser Exadata : votre stockage sera (entre-autres) parfaitement dimensionné et équilibré pour votre base.
Quelques lectures intéressantes :