Durant mes audits, j’ai vu un certain nombre de fois où le(s) sous système(s) disque(s) étai(en)t une des causes principales de problèmes de performances. J’ai eu quelques fois à refaire le plan de répartition des fichiers de bases de données ainsi que l’architecture disque sous jacente qui n’était pas optimale. Pour pouvoir réaliser cette tâche, il est préférable de connaître les caractéristiques d’entrées / sorties appliquées aux fichiers de bases de données et implicitement au(x) sous système(s) disque(s) qui les hébergent. Le script suivant permet de réaliser cette tâche.
Celui-ci permet notamment de connaître le ratio de lecture ou d’écriture pour chaque fichier de base de données, la latence et la quantité moyenne de données pour chaque type d’opération.
Cela peut aider par exemple :
- à la répartition des fichiers de bases de données sur différents axes physiques en fonction de l’activité I/O
- à savoir si un sous système disque est performant (en se basant sur la latence)
- à préparer des tests de performances pour paramétrer un sous système disque en se basant sur la quantité moyenne de données par type d’opération (en conjonction avec SQLIO par exemple).
Â
/***********************************************
* @Author = Mikedavem                         *
* @Description =Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â *
* Statistiques IO sur les fichiers de bases de *
* données                                     *
* Il est possible de classer par :           *
* – Quantité moyenne d’octets par lecture     *
* – Quantité moyenne d’octets par écriture    *
* – Latence moyenne de lecture                *
* – Latence moyenne d’écriture                *
* – Ratio lecture fichier / lecture totale    *
* – Raito écriture fichier / écriture totale  *
************************************************/WITH io_file_stats
AS
(
   SELECT
       d.name AS database_name,
       f.name AS [file_name],
       f.physical_name,
       f.type_desc,
       vf.num_of_reads,
       vf.num_of_writes,
       CAST(vf.num_of_bytes_read * 1. / (vf.num_of_reads + 1) / 1024 AS DECIMAL(18,2)) AS avg_kbytes_read,
       CAST(vf.io_stall_read_ms * 1. / (vf.num_of_reads + 1) AS DECIMAL(18,2)) AS avg_stall_read_ms,
       CAST(vf.num_of_bytes_written * 1. / (vf.num_of_writes + 1) / 1024 AS DECIMAL(18,2)) AS avg_kbytes_written,
       CAST(vf.io_stall_write_ms * 1. / (vf.num_of_writes + 1) AS DECIMAL(18,2)) AS avg_stall_write_ms,
       CAST(vf.num_of_reads * 1. / SUM(num_of_reads + 1) OVER() * 100 AS DECIMAL(5,2)) AS percent_reads,
       CAST(vf.num_of_writes * 1. / SUM(num_of_writes + 1) OVER() *100 AS DECIMAL(5,2)) AS percent_writes
   FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vf
   INNER JOIN sys.databases AS d
   ON d.database_id = vf.database_id
   INNER JOIN sys.master_files AS f
   ON f.file_id = vf.file_id
    AND f.database_id = vf.database_id
),
io_file_stats_rank
AS
(
SELECT
   *,
   RANK() OVER (ORDER BY avg_kbytes_read DESC) AS rank_avg_kbytes_reads,
   RANK() OVER (ORDER BY avg_stall_read_ms DESC) AS rank_avg_stall_read_ms,
   RANK() OVER (ORDER BY avg_kbytes_written DESC) AS rank_avg_kbytes_written,
   RANK() OVER (ORDER BY avg_stall_write_ms DESC) AS rank_avg_stall_write_ms,
   RANK() OVER (ORDER BY percent_reads DESC) AS rank_percent_reads,
   RANK() OVER (ORDER BY percent_writes DESC) AS rank_percent_writes
FROM io_file_stats
)
SELECT
   database_name,
   [file_name],
   physical_name,
   type_desc,
   num_of_reads,
   num_of_writes,
   avg_kbytes_read,
   avg_stall_read_ms,
   avg_kbytes_written,
   avg_stall_write_ms,
   percent_reads,
   percent_writes
FROM io_file_stats_rank
– Choix du classement =
– rank_avg_kbytes_reads
– rank_avg_stall_read_ms
– rank_avg_kbytes_written
– rank_avg_stall_write_ms
– rank_percent_reads
– rank_percent_writes
ORDER BY rank_percent_reads;
Bon audit !!
David BARBARIN (Mikedavem)
Elève ingénieur CNAM Lyon
MVP SQL Server
Salut David,
En principe je vérifie la dernière date de démarrage du serveur pour avoir des statistiques cohérentes.
En général je prends quelques clichés sur une période significative d’activité sur plusieurs jours (du moins j’essaie). Bon en principe tu arrives à récupérer quelque chose de cohérent
Moi j’interpréterais ton résultat autrement à savoir :
Tu as un temps global d’attente de 800s pour une opération effectuée sur disque (lecture ou écriture comprise). Moi je prendrais le différentiel avec le nombre de reads et de writes pendant cette seconde et j’en ferais une moyenne .. io_stall / (numbers_of_reads + numbers_of_writes). Une session pouvant tout à fait lancer plusieurs requêtes en même temps et initier plusieurs demandes I/O. Mais 800 secondes ca fait pas mal tout de même
C’est intéressant mais le pb c’est que tu ne verras pas les pics, comme sys.dm_io_virtual_file_stats() agrège les données depuis le dernier redémarrage. Il faudrait prendre deux clichés à un intervalle fixe (avec un waitfor par exemple) avec ta requête et calculer le différentiel pour chaque ligne pour savoir en instantané combien on a de reads / writes, io stalls, débit, etc…
Cela dit j’ai eu des surprises avec la valeur de io_stalls. C’est sensé renvoyer la durée totale toutes sessions agrégées des io stalls sur l’intervalle. Il y a 2 jours chez un client, je sample toutes les secondes et je me retrouve sur un pic avec 800 secondes de stalls cumulés (en une seconde). Je comprends que ça peut représenter plusieurs sessions mais là quand même, ça voudrait dire que minimum 800 sessions ont attendu 1 seconde pendant l’échantillon, et je n’avais qu’une cinquantaine de sessions sur l’instance… Tu n’as jamais vu de chiffre comme ça ?
A+ David B.
Bonjour,
En ce qui concerne les valeurs la réponse n’est simple. Cela dépend beaucoup du sous système disque utilisé (SAN, carte RAID etc …) et des patterns IO sur ces sous systèmes disques par SQL Server. (Longueur des IO, type séquentiel ou aléatoire etc …)
Cependant les métriques que vous pouvez surveiller sont principalement :
– les IOPS
– le Débit (MB/s)
– Latence (ou temps de réponse)
A titre d’exemple, mon dernier client avait un SAN qui avait les métriques suivantes pour une de ses LUN (RAID 6+2 avec utilisation du cache en écriture) pour 8Ko , lecture , séquentiel : (J’ai arrondi les valeurs)
IOPS : 8000
Débit : 80
Latence : 2 Ã 3 ms
A+
Bonjour,
Merci pour cette requête fort utile.
Par contre, quelles sont les métriques à surveiller en particulier ? A partir de quelle valeurs dois-je commencer à m’inquiéter. Et quelles sont les actions à entreprendre pour corriger ?
Merci beaucoup !