Pourquoi la statistique créée automatiquement sur cette colonne est-elle vide?

8

Info

Ma question concerne une table modérément grande (~ 40 Go d'espace de données) qui est un tas
(malheureusement, je ne suis pas autorisé à ajouter un index clusterisé à la table par les propriétaires d'application)

Une statistique créée automatiquement sur une colonne d'identité ( ID) a été créée, mais elle est vide.

  • Les statistiques de création automatique et de mise à jour automatique sont activées
  • Des modifications ont eu lieu dans le tableau
  • Il existe d'autres statistiques (créées automatiquement) qui sont mises à jour
  • Il existe une autre statistique sur la même colonne créée par un index (en double)
  • Construire: 12.0.5546

La statistique en double est mise à jour: entrez la description de l'image ici

La vraie question

À ma connaissance, toutes les statistiques pourraient être utilisées et les modifications sont suivies, même s'il existe deux statistiques sur exactement les mêmes colonnes (doublons), alors pourquoi cette statistique reste-t-elle vide?

Infos statistiques

entrez la description de l'image ici

Informations sur les statistiques DB

entrez la description de l'image ici

Taille de la table

entrez la description de l'image ici

Informations sur la colonne sur lesquelles la statistique est créée

entrez la description de l'image ici

[ID] [int] IDENTITY(1,1) NOT NULL

Colonne d'identité

select * from sys.stats  
where name like '%_WA_Sys_0000000A_6B7099F3%';

entrez la description de l'image ici Créé automatiquement

Obtenir des informations sur une autre statistique

select * From sys.dm_db_stats_properties (1802541555, 3)  

entrez la description de l'image ici

En comparaison avec ma stat vide:

entrez la description de l'image ici

Stats + Histogramme de "générer des scripts":

/****** Object:  Statistic [_WA_Sys_0000000A_6B7099F3]    Script Date: 2/1/2019 10:18:19 AM ******/

    CREATE STATISTICS [_WA_Sys_0000000A_6B7099F3] ON [dbo].[table]([ID]) WITH STATS_STREAM = 0x01000000010000000000000000000000EC03686B0000000040000000000000000000000000000000380348063800000004000A00000000000000000000000000

Lors de la création d'une copie des statistiques, aucune donnée n'est à l'intérieur

CREATE STATISTICS [_WA_Sys_0000000A_6B7099F3_TEST] ON [dbo].[table]([ID]) WITH STATS_STREAM = 0x01000000010000000000000000000000EC03686B0000000040000000000000000000000000000000380348063800000004000A00000000000000000000000000

entrez la description de l'image ici

Lors de la mise à jour manuelle des statistiques, ils sont mis à jour.

UPDATE STATISTICS [dbo].[Table]([_WA_Sys_0000000A_6B7099F3_TEST])

entrez la description de l'image ici

Randi Vertongen
la source

Réponses:

9

J'ai pu reproduire cela, à la fois avec une statistique vide et une statistique remplie. J'ai organisé une statistique automatique à créer sur une table vide, et l'index a été créé plus tard:

IF OBJECT_ID(N'dbo.Heap', N'U') IS NOT NULL
BEGIN
    DROP TABLE dbo.Heap;
END;
GO
CREATE TABLE dbo.Heap 
(
    id integer NOT NULL IDENTITY,
    val integer NOT NULL,
);
GO
-- Add 1000 rows
INSERT dbo.Heap
    WITH (TABLOCKX)
    (val)
SELECT
    SV.number
FROM master.dbo.spt_values AS SV
WHERE
    SV.[type] = N'P'
    AND SV.number BETWEEN 1 AND 1000;
GO
SELECT COUNT_BIG(*) 
FROM dbo.Heap AS H
JOIN dbo.Heap AS H2
    ON H2.id = H.id
WHERE H.id > 0
AND H2.id > 0;
GO
-- Empty table
TRUNCATE TABLE dbo.Heap;
GO
-- Repeat exact same query (RT = 500 + 0.2 * 1000 = 700)
GO
SELECT COUNT_BIG(*) 
FROM dbo.Heap AS H
JOIN dbo.Heap AS H2
    ON H2.id = H.id
WHERE H.id > 0
AND H2.id > 0;
GO
-- Add 1000 rows
INSERT dbo.Heap
    WITH (TABLOCKX)
    (val)
SELECT
    SV.number
FROM master.dbo.spt_values AS SV
WHERE
    SV.[type] = N'P'
    AND SV.number BETWEEN 1 AND 1000;
GO
-- Add index
ALTER TABLE dbo.Heap ADD 
    CONSTRAINT [PK dbo.Heap id]
    PRIMARY KEY NONCLUSTERED (id);
GO
SELECT
    S.[name],
    S.auto_created,
    DDSP.stats_id,
    DDSP.last_updated,
    DDSP.[rows],
    DDSP.rows_sampled,
    DDSP.steps,
    DDSP.unfiltered_rows,
    DDSP.modification_counter
FROM sys.stats AS S
CROSS APPLY sys.dm_db_stats_properties(S.[object_id], S.stats_id) AS DDSP
WHERE 
    S.[object_id] = OBJECT_ID(N'dbo.Heap', N'U');

Production

J'ai constaté que les modifications continuent d'être suivies avec précision sur tous les doublons non vides, mais une seule statistique est mise à jour automatiquement (quel que soit le paramètre asynchrone).

Les mises à jour automatiques des statistiques se produisent uniquement lorsque l'optimiseur de requêtes a besoin d'une statistique particulière et constate qu'elle est obsolète (une recompilation liée à l'optimalité).

L'optimiseur choisit parmi les statistiques en double comme mentionné dans le plan de mise en cache et de recompilations dans le document SQL Server 2012 :

Un problème qui n'est pas directement lié au sujet de ce document est le suivant: étant donné plusieurs statistiques sur le même ensemble de colonnes dans le même ordre, comment l'optimiseur de requête décide-t-il lesquelles charger lors de l'optimisation de requête? La réponse n'est pas simple, mais l'optimiseur de requêtes utilise des directives telles que: Privilégiez les statistiques récentes aux statistiques plus anciennes; Donner la préférence aux statistiques calculées à l'aide de l' FULLSCANoption à celles calculées à l'aide de l'échantillonnage; etc.

Le fait étant que l'optimiseur choisit l' une des statistiques disponibles en double (la "meilleure") et que celle-ci est automatiquement mise à jour si elle s'avère périmée.

Je pense que c'est un changement de comportement par rapport aux versions antérieures - ou du moins la documentation suggère que toutes les statistiques obsolètes pour un objet seraient mises à jour dans le cadre de ce processus, mais je n'ai aucune idée de quand cela a changé. C'était certainement après août 2013 lorsque Matt Bowler a publié Duplicate Statistics , qui contient un repo pratique basé sur AdventureWorks. Ce script entraîne désormais la mise à jour d'un seul des objets statistiques, alors que les deux l'étaient à l'époque.

L'explication ci-dessus correspond à tous les comportements que j'ai observés en tentant de reproduire votre scénario, mais je doute qu'il soit explicitement documenté n'importe où. Cela semble être une optimisation judicieuse, car il est peu utile de maintenir les doublons à jour.

Tout cela est probablement à un niveau de détail inférieur à celui que Microsoft est prêt à prendre en charge. Cela signifie également qu'il pourrait changer sans préavis.

Paul White 9
la source