Pourquoi ma base de données est-elle toujours fragmentée après avoir tout reconstruit et tout réindexé?

41

J'ai une base de données que j'ai essayé de défragmenter toutes les tables à la fois en exécutant ce T-SQL:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

Et puis copier et coller la sortie dans une nouvelle fenêtre de requête et l'exécuter. Je n'ai pas d'erreur, mais j'ai toujours la fragmentation. J'ai essayé d'exécuter les deux commandes séparément aussi et j'ai toujours une fragmentation. Note: J'ai été informé que REORGANIZEn'est pas nécessaire par Aaron, et je suis conscient que je pourrais utiliser SQL dynamique pour automatiser cela.

J'ai couru ceci pour déterminer qu'il me reste de la fragmentation:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

Et j'ai eu:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

Je sais que quelque chose de fondamental me manque, mais je ne sais pas quoi.

Justin Dearing
la source
Quelles erreurs avez-vous commises? Aussi, y a-t-il une raison pour laquelle vous l'avez réorganisé et reconstruit la même chose?
Shawn Melton le
Shawn, je m'excuse pour le mot qui me manque. Je n'ai aucune erreur. Quant à la raison pour laquelle j’ai exécuté les deux commandes, j’ai fait cela après avoir essayé chaque commande individuellement. J'ai mis à jour mes questions.
Justin Dearing

Réponses:

38

Les tables sont minuscules. Les nombres de pages dans vos tables sont:

11, 8, 6, 5, 13, 8, 10

Ils occupent 480kb au total. Il n'y a littéralement rien à défragmenter.

Edit: Cela justifie un peu plus d'explications.

Une nouvelle table ou un nouvel index se voit généralement attribuer ses 8 premières pages à partir d’une étendue mixte plutôt que uniforme. Il est donc possible que chacune des 8 premières pages soit allouée à partir de différents degrés. Un tableau ou un index consommant 8 pages pourrait donc avoir 8 fragments, 1 sur 8 niveaux différents.

Les scripts de défragmentation les plus largement utilisés (quelques exemples liés ci-dessous) ont tendance à exclure les petites tables pour cette raison. IIRC, <500 pages est dans l’un ou les deux. À ces tailles, la défragmentation ne présente que très peu d’avantages et les chiffres relatifs à la fragmentation sont potentiellement faussés par les attributions à étendue mixte.

Mark Storey-Smith
la source
Ok, c'est satisfaisant à moins que quelqu'un d'autre ait une meilleure réponse, je vais marquer la vôtre comme étant correcte.
Justin Dearing
3
+1 d'accord avec Mark. Inquiétez-vous de la fragmentation alors que vous avez des données. :-)
Aaron Bertrand
Je comprends tout à fait ce que vous dites. Mais juste par pure curiosité, est-ce parce que le moteur de base de données ne peut tout simplement pas défragmenter autant de pages? Je veux dire, il doit y avoir une raison pour cela.
Thomas Stringer le
3
Ce n'est pas que ça ne puisse pas, mais pourquoi cela dérangerait-il? Cela aura peu ou pas d'impact sur les E / S, d'autant plus que les tables de cette taille sont presque toujours garanties en mémoire.
Aaron Bertrand
1
Juste. Cela semble étrange, c'est tout. Supposons que je rédige une application pour vérifier et signaler la fragmentation d'index. Je devrais alors ajouter une logique supplémentaire pour tester le pourcentage de fragmentation, mais également le nombre de pages afin d'éviter les fausses alarmes.
Thomas Stringer le
19

Extrait de " Meilleures pratiques de défragmentation d'index Microsoft SQL Server 2000 ":

"La fragmentation affecte les E / S du disque. Par conséquent, concentrez-vous sur les index les plus volumineux, car leurs pages risquent moins d'être mises en cache par SQL Server. Utilisez le nombre de pages indiqué par DBCC SHOWCONTIG pour avoir une idée de la taille des index (chaque page est utilisée). 8 Ko). en règle générale, vous ne devriez pas être concerné par les niveaux de fragmentation des index avec moins de 1000 pages. dans les tests, les index contenant plus de 10.000 pages réalisé des gains de performance, avec les plus grands gains sur les indices des pages beaucoup plus (plus moins de 50 000 pages) . "

Donc, ce genre de réponse à votre question et soutient les réponses de Mark et Aaron.

Vous pouvez trouver de bonnes informations sur la fragmentation d'index dans les articles suivants de Brent Ozar:

Aussi..un océan d'informations intéressantes sur les index en général (également sur les problèmes de fragmentation) peut être trouvé sur le blog de Kimberly Tripp .

Marian
la source
12

Ceci n’a pas pour but de répondre à votre question, mais cela ne rentrera jamais dans un commentaire. Vous pouvez créer ce script de manière dynamique sans avoir à copier-coller le résultat dans une autre fenêtre. Compte tenu du fait qu'il n'y a absolument aucune raison pour REORGANIZEet ensuite REBUILD:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;
Aaron Bertrand
la source
Aaron, merci d'avoir signalé la dynamique SQL, je connais bien la dynamique SQL, je n'allais pas automatiser la solution tant qu'elle ne fonctionnait pas. D'autres lisant ceci devraient probablement être au courant cependant.
Justin Dearing