web-dev-qa-db-fra.com

Un réindexage met-il à jour les statistiques?

J'ai suivi le cours MS10775A la semaine dernière et une question à laquelle le formateur n'a pas pu répondre de manière fiable est:

Un réindexation met-il à jour les statistiques?

Nous avons trouvé des discussions en ligne faisant valoir à la fois que c'était le cas et que non.

44
Thor Erik

Vous pouvez garder ce qui suit à l'esprit lorsque vous vous souciez de la mise à jour des statistiques (copié à partir de Reconstruction des index contre mise à jour des statistiques (Benjamin Nevarez)

  1. Par défaut, l'instruction UPDATE STATISTICS Utilise uniquement un échantillon d'enregistrements de la table. L'utilisation de UPDATE STATISTICS WITH FULLSCAN Balaye la table entière.

  2. Par défaut, l'instruction UPDATE STATISTICS Met à jour les statistiques d'index et de colonne. L'utilisation de l'option COLUMNS ne mettra à jour que les statistiques des colonnes. L'utilisation de l'option INDEX mettra uniquement à jour les statistiques d'index.

  3. La reconstruction d'un index , par exemple en utilisant ALTER INDEX … REBUILD Mettra également à jour les statistiques d'index avec l'équivalent d'utiliser WITH FULLSCAN sauf la table est partitionnée, auquel cas les statistiques sont uniquement échantillonnées (s'applique à SQL Server 2012 et versions ultérieures).

  4. Les statistiques créées manuellement à l'aide de CREATE STATISTICS Ne sont mises à jour par aucune opération ALTER INDEX ... REBUILD, Y compris ALTER TABLE ... REBUILD. ALTER TABLE ... REBUILD Met à jour les statistiques de l'index clusterisé, si celui-ci est défini sur la table en cours de reconstruction.

  5. La réorganisation d'un index , par exemple en utilisant ALTER INDEX … REORGANIZE Ne met à jour aucune statistique.

La réponse courte est que vous devez utiliser UPDATE STATISTICS Pour mettre à jour les statistiques de colonne et qu'une reconstruction d'index ne mettra à jour que les statistiques d'index. Vous pouvez forcer une mise à jour de toutes les statistiques d'une table, y compris les statistiques d'index et les statistiques créées manuellement, avec la syntaxe UPDATE STATISTICS (tablename) WITH FULLSCAN;.

Le code suivant illustre les règles encapsulées ci-dessus:

Tout d'abord, nous allons créer une table avec quelques colonnes et un index cluster:

USE tempdb;

IF OBJECT_ID(N'dbo.SomeTable', N'U') IS NOT NULL
DROP TABLE dbo.SomeTable;

CREATE TABLE dbo.SomeTable
(
    rn int NOT NULL IDENTITY(1,1)
        CONSTRAINT pk
        PRIMARY KEY NONCLUSTERED
    , i int NOT NULL INDEX i 
    , d sysname NOT NULL
) ON [PRIMARY] WITH (DATA_COMPRESSION = NONE);

CREATE UNIQUE CLUSTERED INDEX cx ON dbo.SomeTable (i, d);

CREATE STATISTICS d ON dbo.SomeTable (d) WITH FULLSCAN;

INSERT INTO dbo.SomeTable (d, i)
SELECT c1.name, c1.id
FROM sys.syscolumns c1;

Cette requête affiche la date de dernière mise à jour de chaque objet stats:

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';

Les résultats montrent qu'aucune mise à jour n'a encore eu lieu, ce qui est correct puisque nous venons de créer le tableau:

╔═══════════════╦═══════════╦═══════════╗ 
 ║ ObjectName ║ StatsName ║ StatsDate ║ 
 ╠═══════════════╬═══════════╬═══════════╣ 
 ║ dbo.SomeTable ║ cx ║ NULL ║ 
 ║ dbo.SomeTable ║ i ║ NULL ║ 
 ║ dbo.SomeTable ║ pk ║ NULL ║ 
 ║ dbo.SomeTable ║ d ║ NULL ║ 
 ╚═══════════════╩═══════════╩═══════════ ╝

Reconstruisons la table entière et voyons si cela met à jour les statistiques:

ALTER TABLE dbo.SomeTable REBUILD;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗ 
 ║ ObjectName ║ StatsName ║ StatsDate ║ 
 ╠═══════════════╬═══════════ ╬═════════════════════════╣ 
 ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ 
 ║ dbo.SomeTable ║ i ║ NULL ║ 
 ║ dbo.SomeTable ║ pk ║ NULL ║ 
 ║ dbo.SomeTable ║ d ║ NULL ║ 
 ╚══ ═════════════╩═══════════╩════════════════════════ ═╝ 

Les résultats montrent que seules les statistiques index cluster ont été mises à jour.

Ensuite, nous effectuons une opération discrète UPDATE STATS:

UPDATE STATISTICS dbo.SomeTable(d) WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';

Comme vous pouvez le voir, nous venons de mettre à jour les statistiques sur la colonne d:

╔═══════════════╦═══════════╦═════════════════════ ════╗ 
 ║ ObjectName ║ StatsName ║ StatsDate ║ 
 ╠═══════════════╬═══════════ ╬═════════════════════════╣ 
 ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ 
 ║ dbo.SomeTable ║ i ║ NULL ║ 
 ║ dbo.SomeTable ║ pk ║ NULL ║ 
 ║ dbo.SomeTable ║ d ║ 2018-09-17 14: 09: 13.597 ║ 
 ╚═══════════════╩═══════════╩═══════════════ ══════════╝

Maintenant, nous mettrons à jour les statistiques sur l'ensemble du tableau:

UPDATE STATISTICS dbo.SomeTable WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗ 
 ║ ObjectName ║ StatsName ║ StatsDate ║ 
 ╠═══════════════╬═══════════ ╬═════════════════════════╣ 
 ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.600 ║ 
 ║ dbo.SomeTable ║ i ║ 2018-09-17 14: 09: 13.600 ║ 
 ║ dbo.SomeTable ║ pk ║ 2018-09-17 14: 09: 13.603 ║ 
 ║ dbo.SomeTable ║ d ║ 2018-09-17 14: 09: 13.607 ║ 
 ╚═══════════════╩═════════ ══╩═════════════════════════╝

Comme vous pouvez le voir, la seule façon d'être certain que toutes les statistiques sont mises à jour est de les mettre à jour manuellement ou de mettre à jour la table entière avec UPDATE STATISTICS (table);.

53
MicSim

La page Microsoft Docs pour les statistiques SQL Server states :

Les opérations telles que la reconstruction, la défragmentation ou la réorganisation d'un index ne modifient pas la distribution des données. Par conséquent, vous n'avez pas besoin de mettre à jour les statistiques après avoir effectué les opérations ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG ou ALTER INDEX REORGANIZE . L'optimiseur de requêtes met à jour les statistiques lorsque vous reconstruisez un index sur une table ou une vue avec ALTER INDEX REBUILD ou DBCC DBREINDEX, mais cette mise à jour des statistiques est un sous-produit de la recréation de l'index. L'optimiseur de requête ne met pas à jour les statistiques après les opérations DBCC INDEXDEFRAG ou ALTER INDEX REORGANIZE.

6
bside