sys.dm_db_index_physical_stats (Transact-SQL)
S’applique à :SQL ServerAzure SQL DatabaseAzure SQL Managed Instance
Retourne des informations de taille et de fragmentation pour les données et les index de la table ou de la vue spécifiées dans le Moteur de base de données SQL Server. Pour un index, une ligne est retournée pour chaque niveau de l'arbre B (B-tree) dans chaque partition. Pour un segment de mémoire, une ligne est retournée pour l’unité d’allocation IN_ROW_DATA
de chaque partition. Pour les données d’objet volumineux (LOB), une ligne est retournée pour l’unité LOB_DATA
d’allocation de chaque partition. Si des données de dépassement de ligne existent dans la table, une ligne est retournée pour l’unité ROW_OVERFLOW_DATA
d’allocation dans chaque partition.
Remarque
De manière générale, la documentation SQL Server utilise le terme B-tree en référence aux index. Dans les index rowstore, le moteur de base de données implémente une structure B+. Cela ne s’applique pas aux index columnstore ou aux index sur les tables à mémoire optimisée. Pour plus d’informations, consultez le Guide de conception et d’architecture d’index SQL Server et Azure SQL.
sys.dm_db_index_physical_stats
ne retourne pas d’informations sur les index optimisés en mémoire. Pour plus d’informations sur l’utilisation de l’index optimisé en mémoire, consultez sys.dm_db_xtp_index_stats.
Si vous interrogez sys.dm_db_index_physical_stats
sur une instance de serveur qui héberge un réplica secondaire lisible par un groupe de disponibilité, vous pouvez rencontrer un REDO
problème de blocage. Cela est dû au fait que cette vue de gestion dynamique acquiert un verrou intention-partagé (IS) sur la table ou la vue utilisateur spécifiée qui peut bloquer les requêtes par un REDO
thread pour un verrou exclusif (X) sur cette table ou vue utilisateur.
Conventions de la syntaxe Transact-SQL
Syntaxe
sys.dm_db_index_physical_stats (
{ database_id | NULL | 0 | DEFAULT }
, { object_id | NULL | 0 | DEFAULT }
, { index_id | NULL | 0 | -1 | DEFAULT }
, { partition_number | NULL | 0 | DEFAULT }
, { mode | NULL | DEFAULT }
)
Arguments
database_id | NULL | 0 | FAIRE DÉFAUT
ID de la base de données.
database_id est petit. Les entrées valides sont l’ID d’une base de données, NULL
ou 0
DEFAULT
. Par défaut, il s’agit de 0
.
NULL
, 0
et DEFAULT
sont des valeurs équivalentes dans ce contexte.
Spécifiez NULL
de retourner des informations pour toutes les bases de données dans l’instance de SQL Server. Si vous spécifiez NULL
pour database_id, vous devez également spécifier NULL
pour object_id, index_id et partition_number.
La fonction intégrée DB_ID peut être spécifiée. Lorsque vous utilisez DB_ID
sans spécifier de nom de base de données, le niveau de compatibilité de la base de données actuelle doit être 90
ou supérieur.
object_id | NULL | 0 | FAIRE DÉFAUT
ID d’objet de la table ou vue sur laquelle l’index est activé. object_id est int. Les entrées valides sont l’ID d’une table et d’une vue, NULL
ou 0
DEFAULT
. Par défaut, il s’agit de 0
.
NULL
, 0
et DEFAULT
sont des valeurs équivalentes dans ce contexte.
Dans SQL Server 2016 (13.x) et versions ultérieures, les entrées valides incluent également le nom de la file d’attente service Broker ou le nom de la table interne de la file d’attente. Lorsque les paramètres par défaut sont appliqués (autrement dit, tous les objets, tous les index, etc.), les informations de fragmentation pour toutes les files d’attente sont incluses dans le jeu de résultats.
Spécifiez NULL
de renvoyer des informations pour toutes les tables et vues de la base de données spécifiée. Si vous spécifiez pour object_id, vous devez également spécifier NULL
pour index_id et NULL
.
index_id | 0 | NULL | -1 | FAIRE DÉFAUT
ID de l’index.
index_id est int. Les entrées valides sont l’ID d’un index, si object_id est un tas, 0
ou NULL
.-1
DEFAULT
Par défaut, il s’agit de -1
.
NULL
, -1
et DEFAULT
sont des valeurs équivalentes dans ce contexte.
Spécifiez NULL
de renvoyer des informations pour tous les index d’une table ou d’une vue de base. Si vous spécifiez NULL
index_id, vous devez également spécifier NULL
pour partition_number.
partition_number | NULL | 0 | FAIRE DÉFAUT
Numéro de partition dans l’objet.
partition_number est int. Les entrées valides sont les partition_number d’un index ou d’un tas, NULL
, 0
ou DEFAULT
. Par défaut, il s’agit de 0
.
NULL
, 0
et DEFAULT
sont des valeurs équivalentes dans ce contexte.
Spécifiez NULL
de renvoyer des informations pour toutes les partitions de l’objet propriétaire.
partition_number est basée sur 1. Un index ou un tas nonpartitionné a partition_number défini sur 1
.
mode | NULL | FAIRE DÉFAUT
Nom du mode.
le mode spécifie le niveau d’analyse utilisé pour obtenir des statistiques.
le mode est sysname. Les entrées valides sont DEFAULT
, , NULL
LIMITED
, SAMPLED
ou DETAILED
. La valeur par défaut (NULL
) est LIMITED
.
Table retournée
Nom de la colonne | Type de données | Description |
---|---|---|
database_id |
smallint | ID de base de données de la table ou de la vue. Dans la base de données Azure SQL, les valeurs sont uniques au sein d’une base de données unique ou d’un pool élastique, mais pas dans un serveur logique. |
object_id |
int | ID d'objet de la table ou de la vue vers laquelle pointe l'index. |
index_id |
int | ID d'index d'un index.0 = Tas. |
partition_number |
int | Numéro de partition de base 1 dans l'objet propriétaire : une table, une vue ou un index.1 = Index ou tas nonpartitionné. |
index_type_desc |
nvarchar(60) | Description du type d’index : - HEAP - CLUSTERED INDEX - NONCLUSTERED INDEX - PRIMARY XML INDEX - EXTENDED INDEX - XML INDEX - COLUMNSTORE MAPPING INDEX (interne)- COLUMNSTORE DELETEBUFFER INDEX (interne)- COLUMNSTORE DELETEBITMAP INDEX (interne) |
alloc_unit_type_desc |
nvarchar(60) | Description du type d'unité d'allocation : - IN_ROW_DATA - LOB_DATA - ROW_OVERFLOW_DATA L’unité LOB_DATA d’allocation contient les données stockées dans des colonnes de type texte, ntext, image, varchar(max), nvarchar(max), varbinary(max) et xml. Pour plus d’informations, consultez Types de données.L’unité ROW_OVERFLOW_DATA d’allocation contient les données stockées dans les colonnes de type varchar(n), nvarchar(n), varbinary(n), et sql_variant qui sont envoyées hors ligne. |
index_depth |
tinyint | Nombre de niveaux d'index.1 = Segment de mémoire ou LOB_DATA ROW_OVERFLOW_DATA unité d’allocation. |
index_level |
tinyint | Niveau actuel de l'index.0 pour les niveaux feuille d’index, les segments de mémoire et LOB_DATA ou ROW_OVERFLOW_DATA les unités d’allocation.Supérieur à 0 celui des niveaux d’index non-sourds.
index_level est le plus élevé au niveau racine d’un index.Les niveaux non-sourds des index ne sont traités que lorsque le mode est DETAILED . |
avg_fragmentation_in_percent |
float | Fragmentation logique pour les index ou fragmentation d’étendue pour les segments de mémoire dans l’unité d’allocation IN_ROW_DATA .La valeur est mesurée en pourcentage et prend en compte plusieurs fichiers. Pour connaître les définitions de fragmentation logique et d’étendue, consultez Remarques. 0 pour et LOB_DATA les ROW_OVERFLOW_DATA unités d’allocation.
NULL pour les tas lorsque le mode est SAMPLED . |
fragment_count |
bigint | Nombre de fragments au niveau feuille d’une unité d’allocation IN_ROW_DATA . Pour plus d’informations sur les fragments, consultez Remarques.NULL pour les niveaux non-sourds d’un index et LOB_DATA ou ROW_OVERFLOW_DATA des unités d’allocation.
NULL pour les tas lorsque le mode est SAMPLED . |
avg_fragment_size_in_pages |
float | Nombre moyen de pages d’un fragment dans le niveau feuille d’une unité d’allocation IN_ROW_DATA .NULL pour les niveaux non-sourds d’un index et LOB_DATA ou ROW_OVERFLOW_DATA des unités d’allocation.
NULL pour les tas lorsque le mode est SAMPLED . |
page_count |
bigint | Nombre total d'index ou de pages de données. Pour un index, nombre total de pages d’index dans le niveau actuel de l’arborescence B dans l’unité IN_ROW_DATA d’allocation.Pour un tas, nombre total de pages de données dans l’unité d’allocation IN_ROW_DATA .Pour LOB_DATA ou ROW_OVERFLOW_DATA unités d’allocation, nombre total de pages dans l’unité d’allocation. |
avg_page_space_used_in_percent |
float | Pourcentage moyen d'espace de stockage disponible utilisé dans toutes les pages. Pour un index, la moyenne s’applique au niveau actuel de l’arborescence B dans l’unité IN_ROW_DATA d’allocation.Pour un tas, la moyenne de toutes les pages de données de l’unité d’allocation IN_ROW_DATA .Pour LOB_DATA ou ROW_OVERFLOW_DATA unités d’allocation, la moyenne de toutes les pages de l’unité d’allocation.
NULL quand le mode est LIMITED . |
record_count |
bigint | Nombre total d'enregistrements. Pour un index, le nombre total d’enregistrements s’applique au niveau actuel de l’arborescence B dans l’unité IN_ROW_DATA d’allocation.Pour un tas, nombre total d’enregistrements dans l’unité d’allocation IN_ROW_DATA .Remarque : Pour un tas, le nombre d’enregistrements retournés à partir de cette fonction peut ne pas correspondre au nombre de lignes retournées par l’exécution d’un SELECT COUNT(*) segment de mémoire. Cela est dû au fait qu’une ligne peut contenir plusieurs enregistrements. Par exemple, dans certaines situations de mise à jour, une seule ligne de tas peut avoir un enregistrement de transfert et un enregistrement transféré suite à l’opération de mise à jour. En outre, la plupart des lignes métier volumineuses sont divisées en plusieurs enregistrements dans le LOB_DATA stockage.Pour LOB_DATA ou ROW_OVERFLOW_DATA unités d’allocation, nombre total d’enregistrements dans l’unité d’allocation complète.
NULL quand le mode est LIMITED . |
ghost_record_count |
bigint | Nombre d'enregistrements fantômes prêts à être supprimés par la tâche de nettoyage des enregistrements fantômes dans l'unité d'allocation.0 pour les niveaux non-sourds d’un index dans l’unité d’allocation IN_ROW_DATA .
NULL quand le mode est LIMITED . |
version_ghost_record_count |
bigint | Nombre d'enregistrements fantômes retenus par une transaction d'isolation d'instantané en attente dans une unité d'allocation.0 pour les niveaux non-sourds d’un index dans l’unité d’allocation IN_ROW_DATA .
NULL quand le mode est LIMITED . |
min_record_size_in_bytes |
int | Taille minimale des enregistrements en octets. Pour un index, la taille minimale des enregistrements s’applique au niveau actuel de l’arborescence B dans l’unité IN_ROW_DATA d’allocation.Pour un tas, taille d’enregistrement minimale dans l’unité d’allocation IN_ROW_DATA .Pour LOB_DATA ou ROW_OVERFLOW_DATA unités d’allocation, taille d’enregistrement minimale dans l’unité d’allocation complète.
NULL quand le mode est LIMITED . |
max_record_size_in_bytes |
int | Taille maximale des enregistrements en octets. Pour un index, la taille maximale d’enregistrement s’applique au niveau actuel de l’arborescence B dans l’unité IN_ROW_DATA d’allocation.Pour un tas, taille maximale d’enregistrement dans l’unité d’allocation IN_ROW_DATA .Pour LOB_DATA ou ROW_OVERFLOW_DATA unités d’allocation, taille maximale d’enregistrement dans l’unité d’allocation complète.
NULL quand le mode est LIMITED . |
avg_record_size_in_bytes |
float | Taille moyenne des enregistrements en octets. Pour un index, la taille moyenne des enregistrements s’applique au niveau actuel de l’arborescence B dans l’unité IN_ROW_DATA d’allocation.Pour un tas, la taille moyenne des enregistrements dans l’unité d’allocation IN_ROW_DATA .Pour LOB_DATA ou ROW_OVERFLOW_DATA pour les unités d’allocation, la taille moyenne des enregistrements dans l’unité d’allocation complète.
NULL quand le mode est LIMITED . |
forwarded_record_count |
bigint | Nombre d'enregistrements d'un segment de mémoire qui contiennent des pointeurs avant vers un autre emplacement de données. (Cet état se produit lors d’une mise à jour, lorsqu’il n’y a pas suffisamment de place pour stocker la nouvelle ligne à l’emplacement d’origine.)NULL pour toute unité d’allocation autre que les IN_ROW_DATA unités d’allocation d’un tas.
NULL pour les tas lorsque le mode est LIMITED . |
compressed_page_count |
bigint | Nombre de pages compressées. Pour les tas, les pages nouvellement allouées ne sont pas PAGE compressées. Un tas est PAGE compressé dans deux conditions spéciales : lorsque les données sont importées en bloc ou lorsqu’un tas est reconstruit. Les opérations DML classiques qui provoquent l’allocation de pages ne sont pas PAGE compressées. Régénérez un tas lorsque la compressed_page_count valeur augmente plus grande que le seuil souhaité.Pour les tables qui ont un index cluster, la compressed_page_count valeur indique l’efficacité de PAGE la compression. |
hobt_id |
bigint | Segment de mémoire ou ID d’arborescence B de l’index ou de la partition. Pour les index columnstore, il s’agit de l’ID d’un ensemble de lignes qui effectue le suivi des données de columnstore internes pour une partition. Les ensembles de lignes sont stockés sous forme de tas de données ou d’arborescences B. Ils ont le même ID d’index que l’index columnstore parent. Pour plus d’informations, consultez sys.internal_partitions. |
columnstore_delete_buffer_state |
tinyint | 0 = NOT_APPLICABLE 1 = OPEN 2 = DRAINING 3 = FLUSHING 4 = RETIRING 5 = READY S’applique à : SQL Server 2016 (13.x) et versions ultérieures, Azure SQL Database et Azure SQL Managed Instance |
columnstore_delete_buffer_state_desc |
nvarchar(60) |
NOT VALID - l’index parent n’est pas un index columnstore.OPEN - les deleters et les scanneurs l’utilisent.DRAINING - les deleters se vident, mais les scanneurs l’utilisent toujours.FLUSHING - la mémoire tampon est fermée et les lignes de la mémoire tampon sont écrites dans la bitmap de suppression.RETIRING : les lignes de la mémoire tampon de suppression fermée ont été écrites dans la bitmap de suppression, mais la mémoire tampon n’a pas été tronquée, car les scanneurs l’utilisent toujours. Les nouveaux scanneurs n’ont pas besoin d’utiliser la mémoire tampon de mise hors service, car la mémoire tampon ouverte est suffisante.READY - Cette mémoire tampon de suppression est prête à être utilisée.S’applique à : SQL Server 2016 (13.x) et versions ultérieures, Azure SQL Database et Azure SQL Managed Instance |
version_record_count |
bigint | Il s’agit du nombre d’enregistrements de version de ligne conservés dans cet index. Ces versions de ligne sont gérées par la fonctionnalité de récupération de base de données accélérée. S’applique à : SQL Server 2019 (15.x) et versions ultérieures, et Azure SQL Database |
inrow_version_record_count |
bigint | Nombre d’enregistrements de version ADR conservés dans la ligne de données pour une récupération rapide. S’applique à : SQL Server 2019 (15.x) et versions ultérieures, et Azure SQL Database |
inrow_diff_version_record_count |
bigint | Nombre d’enregistrements de version ADR conservés sous la forme de différences par rapport à la version de base. S’applique à : SQL Server 2019 (15.x) et versions ultérieures, et Azure SQL Database |
total_inrow_version_payload_size_in_bytes |
bigint | Taille totale en octets des enregistrements de version en ligne pour cet index. S’applique à : SQL Server 2019 (15.x) et versions ultérieures, et Azure SQL Database |
offrow_regular_version_record_count |
bigint | Nombre d’enregistrements de version conservés en dehors de la ligne de données d’origine. S’applique à : SQL Server 2019 (15.x) et versions ultérieures, et Azure SQL Database |
offrow_long_term_version_record_count |
bigint | Nombre d’enregistrements de version considérés comme à long terme. S’applique à : SQL Server 2019 (15.x) et versions ultérieures, et Azure SQL Database |
Remarque
De manière générale, la documentation SQL Server utilise le terme B-tree en référence aux index. Dans les index rowstore, le moteur de base de données implémente une structure B+. Cela ne s’applique pas aux index columnstore ou aux index sur les tables à mémoire optimisée. Pour plus d’informations, consultez le Guide de conception et d’architecture d’index SQL Server et Azure SQL.
Notes
La fonction de gestion dynamique sys.dm_db_index_physical_stats
remplace l’instruction DBCC SHOWCONTIG
.
Modes d’analyse
Le mode d'exécution de la fonction détermine le niveau de l'analyse effectuée pour obtenir les données statistiques utilisées par la fonction.
le mode est spécifié en tant que LIMITED
, SAMPLED
ou DETAILED
. La fonction traverse les chaînes de pages des unités d'allocation qui composent les partitions spécifiées de la table ou de l'index.
sys.dm_db_index_physical_stats
nécessite uniquement un verrou de table Intention-Shared (IS), quel que soit le mode dans lequel il s’exécute.
Le LIMITED
mode est le mode le plus rapide et analyse le plus petit nombre de pages. Pour un index, seules les pages de niveau parent de l'arbre B (B-tree) (autrement dit, les pages au-dessus du niveau feuille) sont analysées. Pour un tas, les pages PFS et IAM associées sont examinées et les pages de données d’un tas sont analysées en LIMITED
mode.
Avec LIMITED
le mode, compressed_page_count
c’est NULL
parce que le Moteur de base de données analyse uniquement les pages non-sourdes de l’arborescence B et les pages IAM et PFS du tas. Utilisez SAMPLED
le mode pour obtenir une valeur estimée pour compressed_page_count
, et utilisez DETAILED
le mode pour obtenir la valeur réelle pour compressed_page_count
. Le SAMPLED
mode retourne des statistiques basées sur un échantillon de 1 % de toutes les pages de l’index ou du tas. Les résultats en SAMPLED
mode doivent être considérés comme approximatifs. Si l’index ou le tas a moins de 10 000 pages, DETAILED
le mode est utilisé au lieu de SAMPLED
.
Le DETAILED
mode analyse toutes les pages et retourne toutes les statistiques.
Les modes sont progressivement plus lents à LIMITED
partir de DETAILED
, car plus de travail est effectué dans chaque mode. Pour évaluer rapidement la taille ou le niveau de fragmentation d’une table ou d’un index, utilisez le LIMITED
mode. Il s’agit du plus rapide et ne retourne pas de ligne pour chaque niveau non sourd dans l’unité IN_ROW_DATA
d’allocation de l’index.
Utiliser des fonctions système pour spécifier des valeurs de paramètre
Vous pouvez utiliser les fonctions Transact-SQL DB_ID et OBJECT_ID pour spécifier une valeur pour les paramètres database_id et object_id . Toutefois, le passage de valeurs qui ne sont pas valides à ces fonctions peut entraîner des résultats inattendus. Par exemple, si le nom de la base de données ou de l’objet n’est pas trouvé parce qu’il n’existe pas ou qu’il n’existe pas correctement, les deux fonctions retournent NULL
. La sys.dm_db_index_physical_stats
fonction interprète NULL
comme une valeur générique spécifiant toutes les bases de données ou tous les objets.
En outre, la OBJECT_ID
fonction est traitée avant l’appel de la sys.dm_db_index_physical_stats
fonction et est donc évaluée dans le contexte de la base de données active, et non dans la base de données spécifiée dans database_id. Ce comportement peut entraîner le retour d’une OBJECT_ID
valeur par la NULL
fonction ; ou, si le nom de l’objet existe à la fois dans le contexte de base de données actuel et la base de données spécifiée, un message d’erreur est retourné. Les exemples suivants présentent ces résultats inattendus.
USE master;
GO
-- In this example, OBJECT_ID is evaluated in the context of the master database.
-- Because Person.Address does not exist in master, the function returns NULL.
-- When NULL is specified as an object_id, all objects in the database are returned.
-- The same results are returned when an object that is not valid is specified.
SELECT * FROM sys.dm_db_index_physical_stats
(DB_ID(N'AdventureWorks2022'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- This example demonstrates the results of specifying a valid object name
-- that exists in both the current database context and
-- in the database specified in the database_id parameter of the
-- sys.dm_db_index_physical_stats function.
-- An error is returned because the ID value returned by OBJECT_ID does not
-- match the ID value of the object in the specified database.
CREATE DATABASE Test;
GO
USE Test;
GO
CREATE SCHEMA Person;
GO
CREATE Table Person.Address(c1 int);
GO
USE AdventureWorks2022;
GO
SELECT * FROM sys.dm_db_index_physical_stats
(DB_ID(N'Test'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- Clean up temporary database.
DROP DATABASE Test;
GO
Bonnes pratiques
Vérifiez toujours qu’un ID valide est retourné lorsque vous utilisez DB_ID
ou OBJECT_ID
. Par exemple, lorsque vous utilisez OBJECT_ID
, spécifiez un nom en trois parties, tel que OBJECT_ID(N'AdventureWorks2022.Person.Address')
, ou testez la valeur retournée par les fonctions avant de les utiliser dans la sys.dm_db_index_physical_stats
fonction. Les exemples A et B qui suivent illustrent une méthode sûre pour déterminer des ID de bases de données et d'objets.
Détecter la fragmentation
La fragmentation se produit par le processus de modifications de données (INSERT
, UPDATE
et DELETE
d’instructions) effectuées sur la table et, par conséquent, aux index définis sur la table. Étant donné que ces modifications ne sont généralement pas distribuées de manière égale entre les lignes de la table et des index, l’intégralité de chaque page peut varier au fil du temps. Pour les requêtes qui analysent une partie ou l’ensemble des index d’une table, ce type de fragmentation peut entraîner des lectures de pages supplémentaires, ce qui entrave l’analyse parallèle des données.
Le niveau de fragmentation d’un index ou d’un tas est affiché dans la avg_fragmentation_in_percent
colonne. Pour les segments de mémoire, cette valeur représente la fragmentation de l'étendue du segment. Pour les index, cette valeur représente la fragmentation logique de l'index. Contrairement DBCC SHOWCONTIG
aux algorithmes de calcul de fragmentation dans les deux cas, considérez le stockage qui s’étend sur plusieurs fichiers et, par conséquent, sont précis.
Fragmentation logique
Pourcentage de pages hors service dans les pages de feuilles d'un index. Une page non ordonnée est une page pour laquelle la page physique suivante allouée à l’index n’est pas la page désignée par le pointeur de page suivante dans la page feuille actuelle.
Fragmentation de l’étendue
Pourcentage d'étendues hors service dans les pages de feuilles d'un segment de mémoire. Une extension hors ordre est une pour laquelle l’étendue qui contient la page active d’un tas n’est pas physiquement l’extension suivante après l’étendue qui contient la page précédente.
La valeur pour avg_fragmentation_in_percent
laquelle doit être aussi proche de zéro que possible pour des performances maximales. Toutefois, les valeurs comprises entre 0 et 10 % peuvent être acceptables. Toutes les méthodes de réduction de la fragmentation, telles que la reconstruction, la réorganisation ou la recréation, peuvent être utilisées pour réduire ces valeurs. Pour plus d’informations sur l’analyse du degré de fragmentation dans un index, consultez Optimiser la maintenance des index pour améliorer les performances des requêtes et réduire la consommation des ressources.
Réduire la fragmentation dans un index
Lorsqu'un index est fragmenté de telle façon que la fragmentation nuit aux performances des requêtes, il existe trois possibilités de réduction de la fragmentation :
Supprimez et recréez l’index cluster.
La recréation d’un index cluster redistribue les données et génère des pages de données complètes. Vous pouvez configurer le niveau de remplissage en spécifiant l'option
FILLFACTOR
dansCREATE INDEX
. Les inconvénients de cette méthode sont que l’index est hors connexion pendant le cycle de suppression et de recréation, et que l’opération est atomique. Si la création de l’index est interrompue, l’index n’est pas recréé. Pour plus d’informations, consultez CREATE INDEX.Utilisez
ALTER INDEX REORGANIZE
, le remplacement pourDBCC INDEXDEFRAG
, pour réorganiser les pages de niveau feuille de l’index dans un ordre logique. Du fait qu'il s'agit d'une opération en ligne, l'index est disponible lorsque l'instruction est en cours d'exécution. Il est également possible d'interrompre l'opération sans perdre le travail déjà effectué. L’inconvénient de cette méthode est qu’elle ne fonctionne pas aussi bien pour réorganiser les données en tant qu’opération de reconstruction d’index, et qu’elle ne met pas à jour les statistiques.Utilisez
ALTER INDEX REBUILD
, le remplacement pourDBCC DBREINDEX
, pour reconstruire l’index en ligne ou hors connexion. Pour plus d’informations, consultez ALTER INDEX (Transact-SQL).
La fragmentation seule n’est pas une raison suffisante pour réorganiser ou reconstruire un index. Le principal effet de la fragmentation est le ralentissement de la lecture anticipée lors de l'analyse d'un index. Les temps de réponse sont donc plus longs. Si la charge de travail de requête sur une table ou un index fragmenté n’implique pas d’analyses, car la charge de travail est principalement des recherches singleton, la suppression de la fragmentation ne peut avoir aucun effet.
Remarque
L’exécution DBCC SHRINKFILE
ou DBCC SHRINKDATABASE
l’introduction d’une fragmentation si un index est partiellement ou complètement déplacé pendant l’opération de réduction. Par conséquent, si une opération de compactage doit être effectuée, vous devez l'exécuter avant la suppression de la fragmentation.
Réduire la fragmentation dans un tas
Pour réduire la fragmentation de l'étendue d'un segment de mémoire, créez un index cluster sur la table puis supprimez l'index. Cela redistribue les données pendant la création de l'index cluster. Si l'on considère l'espace disponible dans la base de données, l'organisation des données est également optimale. Lorsque l’index cluster est ensuite supprimé pour recréer le tas, les données ne sont pas déplacées et restent de façon optimale en position. Pour plus d’informations sur l’exécution de ces opérations, consultez CREATE INDEX et DROP INDEX.
Attention
La création et la suppression d’un index cluster sur une table reconstruit tous les index non cluster sur cette table deux fois.
Compacter des données d’objet volumineux
Par défaut, l’instruction ALTER INDEX REORGANIZE
compacte les pages qui contiennent des données d’objet volumineux (LOB). Étant donné que les pages métier ne sont pas libérées lorsqu’elles sont vides, le compactage de ces données peut améliorer l’espace disque utilisé si un grand nombre de données métier est supprimé ou qu’une colonne métier est supprimée.
La réorganisation d'un index cluster spécifié compacte toutes les colonnes LOB contenues dans l'index cluster. La réorganisation d'un index non cluster compacte toutes les colonnes LOB qui sont des colonnes non-clés (incluses) dans l'index. Quand ALL
elle est spécifiée dans l’instruction, tous les index associés à la table ou à la vue spécifiées sont réorganisés. En outre, toutes les colonnes métier associées à l’index cluster, à la table sous-jacente ou à l’index non cluster avec des colonnes incluses sont compactées.
Évaluer l’utilisation de l’espace disque
La avg_page_space_used_in_percent
colonne indique l’intégralité de la page. Pour obtenir une utilisation optimale de l’espace disque, cette valeur doit être proche de 100 % pour un index qui n’a pas beaucoup d’insertions aléatoires. Toutefois, un index qui a de nombreux insertions aléatoires et a des pages très pleines ont un nombre accru de fractionnements de pages. Cela implique une fragmentation plus importante. Par conséquent, pour réduire les fractionnements, la valeur doit être inférieure à 100 %. La reconstruction d’un index avec l’option FILLFACTOR
spécifiée permet de modifier l’intégralité de la page pour qu’elle corresponde au modèle de requête sur l’index. Pour plus d’informations sur le facteur de remplissage, consultez Spécifier un facteur de remplissage pour un index. En outre, ALTER INDEX REORGANIZE
compacter un index en essayant de remplir les pages à la FILLFACTOR
dernière spécification. Cela augmente la valeur de avg_space_used_in_percent.
ALTER INDEX REORGANIZE
ne peut pas réduire l’intégralité de la page. Au lieu de cela, une reconstruction de l'index doit avoir lieu.
Évaluer les fragments d’index
Un fragment se compose de pages de feuilles physiquement contiguës dans le même fichier d'une unité d'allocation. Un index comporte au moins un fragment. Le nombre maximal de fragments d'un index est égal au nombre de pages du niveau feuille de l'index. Des fragments plus importants signifient que moins d'opérations d'entrées/sorties sur le disque sont nécessaires pour lire le même nombre de pages. Par conséquent, plus la valeur est avg_fragment_size_in_pages
grande, plus les performances d’analyse de plage sont meilleures. Les avg_fragment_size_in_pages
valeurs et avg_fragmentation_in_percent
les valeurs sont inversement proportionnelles les unes aux autres. La reconstruction ou la réorganisation d'un index doit donc réduire la quantité de fragmentation et augmenter la taille des fragments.
Limites
Ne retourne pas de données pour les index columnstore en cluster.
autorisations
Les autorisations suivantes sont nécessaires :
CONTROL
autorisation sur l’objet spécifié dans la base de données.VIEW DATABASE STATE
ouVIEW DATABASE PERFORMANCE STATE
(SQL Server 2022) autorisation de retourner des informations sur tous les objets de la base de données spécifiée, à l’aide du caractère générique =NULL
.VIEW SERVER STATE
ouVIEW SERVER PERFORMANCE STATE
(SQL Server 2022) autorisation de retourner des informations sur toutes les bases de données, à l’aide du caractère générique =NULL
.
L’octroi VIEW DATABASE STATE
permet à tous les objets de la base de CONTROL
données d’être retournés, quelles que soient les autorisations refusées sur des objets spécifiques.
VIEW DATABASE STATE
Refuser que tous les objets de la base de CONTROL
données soient retournés, quelles que soient les autorisations accordées sur des objets spécifiques. En outre, lorsque le caractère générique de la base de données @database_id = NULL
est spécifié, la base de données est omise.
Pour plus d’informations, consultez vues de gestion dynamique système.
Exemples
Les exemples de code Transact-SQL de cet article sont fondés sur l’échantillon de base de données AdventureWorks2022
ou AdventureWorksDW2022
fourni, que vous pouvez télécharger à partir de la page d’accueil Échantillons et projets communautaires Microsoft SQL Server.
R : Retourner des informations sur une table spécifiée
L'exemple de code suivant retourne des statistiques de taille et de fragmentation sur tous les index et partitions de la table Person.Address
. Le mode d'analyse est défini à LIMITED
pour améliorer les performances et limiter les statistiques retournées. L’exécution de cette requête nécessite, au minimum, CONTROL
une autorisation sur la Person.Address
table.
DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.Person.Address');
IF @db_id IS NULL
BEGIN;
PRINT N'Invalid database';
END;
ELSE IF @object_id IS NULL
BEGIN;
PRINT N'Invalid object';
END;
ELSE
BEGIN;
SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , 'LIMITED');
END;
GO
B. Retourner des informations sur un tas
Le code exemple suivant retourne toutes les statistiques sur le segment de mémoire dbo.DatabaseLog
de la base de données AdventureWorks2022
. Comme la table contient des données LOB, une ligne est retournée pour l'unité d'allocation LOB_DATA
, en plus de la ligne retournée pour l'unité d'allocation IN_ROW_ALLOCATION_UNIT
qui stocke les pages de données du segment de mémoire. L’exécution de cette requête nécessite, au minimum, CONTROL
une autorisation sur la dbo.DatabaseLog
table.
DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.dbo.DatabaseLog');
IF @object_id IS NULL
BEGIN;
PRINT N'Invalid object';
END;
ELSE
BEGIN;
SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, 0, NULL , 'DETAILED');
END;
GO
C. Retourner des informations pour toutes les bases de données
L’exemple suivant retourne toutes les statistiques de toutes les tables et index dans l’instance de SQL Server en spécifiant le caractère générique NULL
pour tous les paramètres. L’exécution de cette requête nécessite l’autorisation VIEW SERVER STATE
.
SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);
GO
D. Utiliser sys.dm_db_index_physical_stats dans un script pour reconstruire ou réorganiser des index
Le code exemple suivant réorganise ou reconstruit automatiquement toutes les partitions d'une base de données dont la fragmentation moyenne est supérieure à 10 %. L’exécution de cette requête nécessite l’autorisation VIEW DATABASE STATE
. Cet exemple spécifie DB_ID
en tant que premier paramètre sans fournir de nom de base de données.
-- Ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;
DECLARE @objectid INT;
DECLARE @indexid INT;
DECLARE @partitioncount BIGINT;
DECLARE @schemaname NVARCHAR(130);
DECLARE @objectname NVARCHAR(130);
DECLARE @indexname NVARCHAR(130);
DECLARE @partitionnum BIGINT;
DECLARE @partitions BIGINT;
DECLARE @frag FLOAT;
DECLARE @command NVARCHAR(4000);
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT object_id AS objectid,
index_id AS indexid,
partition_number AS partitionnum,
avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0
AND index_id > 0;
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR
FOR
SELECT *
FROM #work_to_do;
-- Open the cursor.
OPEN partitions;
-- Loop through the partitions.
WHILE (1 = 1)
BEGIN;
FETCH NEXT
FROM partitions
INTO @objectid,
@indexid,
@partitionnum,
@frag;
IF @@FETCH_STATUS < 0
BREAK;
SELECT @objectname = QUOTENAME(o.name),
@schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
INNER JOIN sys.schemas AS s
ON s.schema_id = o.schema_id
WHERE o.object_id = @objectid;
SELECT @indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = @objectid
AND index_id = @indexid;
SELECT @partitioncount = count(*)
FROM sys.partitions
WHERE object_id = @objectid
AND index_id = @indexid;
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
IF @frag < 30.0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
IF @frag >= 30.0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
IF @partitioncount > 1
SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS NVARCHAR(10));
EXEC (@command);
PRINT N'Executed: ' + @command;
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
-- Drop the temporary table.
DROP TABLE #work_to_do;
GO
E. Utilisez sys.dm_db_index_physical_stats pour afficher le nombre de pages compressées par page
L'exemple suivant montre comment afficher et comparer le nombre total de pages par rapport aux pages qui sont compressées par ligne et par page. Ces informations peuvent être utilisées pour déterminer l'avantage que procure la compression pour un index ou une table.
SELECT o.name,
ips.partition_number,
ips.index_type_desc,
ips.record_count,
ips.avg_record_size_in_bytes,
ips.min_record_size_in_bytes,
ips.max_record_size_in_bytes,
ips.page_count,
ips.compressed_page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
INNER JOIN sys.objects o
ON o.object_id = ips.object_id
ORDER BY record_count DESC;
F. Utiliser sys.dm_db_index_physical_stats en mode SAMPLED
L’exemple suivant montre comment SAMPLED
le mode retourne une valeur approximative différente des résultats du DETAILED
mode.
CREATE TABLE t3 (
col1 INT PRIMARY KEY,
col2 VARCHAR(500)
)
WITH (DATA_COMPRESSION = PAGE);
GO
BEGIN TRANSACTION
DECLARE @idx INT = 0;
WHILE @idx < 1000000
BEGIN
INSERT INTO t3 (col1, col2)
VALUES (
@idx,
REPLICATE('a', 100) + CAST(@idx AS VARCHAR(10)) + REPLICATE('a', 380)
)
SET @idx = @idx + 1
END
COMMIT;
GO
SELECT page_count,
compressed_page_count,
forwarded_record_count,
*
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'SAMPLED');
SELECT page_count,
compressed_page_count,
forwarded_record_count,
*
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'DETAILED');
G. Interroger les files d’attente service broker pour la fragmentation d’index
S’applique à : SQL Server 2016 (13.x) et versions ultérieures
L’exemple suivant montre comment interroger les files d’attente du répartiteur de serveur pour la fragmentation.
--Using queue internal table name
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('sys.queue_messages_549576996'), DEFAULT, DEFAULT, DEFAULT);
--Using queue name directly
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('ExpenseQueue'), DEFAULT, DEFAULT, DEFAULT);
Contenu connexe
- Vues de gestion dynamique système
- Fonctions et vues de gestion dynamique associées à l’index (Transact-SQL)
- sys.dm_db_index_operational_stats (Transact-SQL)
- sys.dm_db_index_usage_stats (Transact-SQL)
- sys.dm_db_partition_stats (Transact-SQL)
- sys.allocation_units (Transact-SQL)
- Guide de référence Transact-SQL (Moteur de base de données)