Je ne sais pas si c'est un bug, en soi mais c'est certainement un événement intéressant. Les reconstructions de partition en ligne sont nouvelles dans SQL Server 2014, il peut donc y avoir des éléments internes à trier avec cela.
Voici ma meilleure explication pour vous. Les statistiques incrémentielles nécessitent absolument que toutes les partitions soient échantillonnées au même rythme afin que lorsque le moteur fusionne les pages de statistiques, il puisse être sûr que la distribution échantillonnée est comparable. REBUILD
échantillonne nécessairement les données à un taux d'échantillonnage de 100%. Il n'y a aucune garantie que le taux d'échantillonnage de 100% sur la partition 9 sera toujours le taux d'échantillonnage exact des autres partitions. Pour cette raison, il semble que le moteur ne puisse pas fusionner les échantillons et vous vous retrouvez avec un blob de statistiques vide. Cependant, l'objet de statistiques est toujours là:
select
check_time = sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
stats_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
outer apply sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
where t.name = 'TransactionHistory' and sh.name = 'dbo'
Vous pouvez remplir le blob par n'importe quel nombre de moyens:
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;
ou
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);
ou vous pouvez attendre la mise à jour d'AutoStats lors de la première compilation d'un plan de requête à l'aide de cet objet:
-- look at my creative query
select *
from dbo.TransactionHistory
where TransactionDate = '20140101';
Cela dit, ce message édifiant d'Erin Stellato met en évidence ce qui est désormais perçu comme une lacune majeure des statistiques incrémentielles. Leurs données au niveau de la partition ne sont pas utilisées par l'optimiseur dans la génération du plan de requête, ce qui réduit l'avantage présumé des statistiques incrémentielles. Quel est donc l’avantage actuel des statistiques incrémentielles? Je dirais que leur utilité principale est de pouvoir échantillonner de grands tableaux de manière plus cohérente à un taux plus élevé qu'avec les statistiques traditionnelles.
En utilisant votre exemple, voici à quoi les choses ressemblent:
set statistics time on;
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 94 ms, elapsed time = 131 ms.
update statistics dbo.TransactionHistory(IDX_ProductId)
with resample on partitions(2);
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 5 ms.
drop index IDX_ProductId On dbo.TransactionHistory;
CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId)
WITH (DATA_COMPRESSION = ROW)
ON [PRIMARY]
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 76 ms, elapsed time = 66 ms.
Une mise à jour complète des statistiques sur la statistique incrémentielle coûte 131 ms. Une mise à jour complète des statistiques sur la statistique non alignée sur les partitions coûte 66 ms. La statistique non alignée est plus lente, probablement en raison des frais généraux occasionnés par la fusion des pages de statistiques individuelles dans l'histogramme principal.. Cependant, en utilisant l'objet statistique aligné sur la partition, nous pouvons mettre à jour une partition et la fusionner à nouveau dans le blob d'histogramme principal en 5 ms. Donc, à ce stade, l'administrateur avec la statistique incrémentale est confronté à une décision. Ils peuvent réduire leur temps de maintenance des statistiques globales en ne mettant à jour que les mises à jour des partitions, ou ils peuvent expérimenter avec des taux d'échantillonnage plus élevés de sorte qu'ils obtiennent potentiellement plus de lignes échantillonnées dans la même période de temps que leur calendrier de maintenance précédent. Le premier permet de respirer dans la fenêtre de maintenance, le second peut pousser les statistiques sur une très grande table vers un endroit où les requêtes obtiennent de meilleurs plans basés sur des statistiques plus précises. Ce n'est pas une garantie et votre kilométrage peut varier.
Le lecteur peut voir que 66 ms n'est pas un temps de mise à jour des statistiques pénible sur ce tableau, j'ai donc essayé de configurer un test sur l'ensemble de données stackexchange. Il y a 6 418 608 messages (à l'exclusion des messages StackOverflow et tous les messages de 2012 - une erreur de données de ma part) dans le récent vidage que j'ai téléchargé.
J'ai partitionné les données par [CreationDate]
parce que ... démo.
Voici quelques timings pour certains scénarios assez standard (100% - reconstruction d'index, par défaut - mise à jour automatique des statistiques ou UPDATE STATISTICS
sans taux d'échantillonnage spécifié:
- Créer une statistique non incrémentielle avec Fullscan: temps CPU = 23500 ms, temps écoulé = 22521 ms.
- Créer une statistique incrémentielle avec Fullscan: temps CPU = 20406 ms, temps écoulé = 15413 ms.
- Mettre à jour la statistique non incrémentielle avec la fréquence d'échantillonnage par défaut: temps CPU = 406 ms, temps écoulé = 408 ms.
- Mettre à jour la statistique incrémentielle avec la fréquence d'échantillonnage par défaut: temps CPU = 453 ms, temps écoulé = 507 ms.
Disons que nous sommes plus sophistiqués que ces scénarios par défaut et avons décidé qu'un taux d'échantillonnage de 10% est le taux minimum qui devrait nous fournir les plans dont nous avons besoin tout en maintenant le temps de maintenance à un délai raisonnable.
- Mettre à jour la statistique non incrémentielle avec un échantillon de 10%: temps CPU = 2344 ms, temps écoulé = 2441 ms.
- Mettre à jour la statistique incrémentielle avec un échantillon de 10%: temps CPU = 2344 ms, temps écoulé = 2388 ms.
Jusqu'à présent, il n'y a aucun avantage clair à avoir une statistique incrémentale. Cependant, si nous exploitons le DMV non documenté sys.dm_db_stats_properties_internal()
(ci-dessous), vous pouvez obtenir un aperçu de la ou des partitions que vous souhaitez mettre à jour. Disons que nous avons apporté des modifications aux données de la partition 3 et que nous voulons nous assurer que les statistiques sont actualisées pour les requêtes entrantes. Voici nos options:
- Mise à jour non incrémentielle par défaut (également le comportement par défaut de la mise à jour automatique des statistiques): 408 ms.
- Mise à jour non incrémentielle à 10%: 2441 ms.
- Mettre à jour les statistiques incrémentielles, partition 3 avec rééchantillonnage (10% - notre taux d'échantillonnage défini): temps CPU = 63 ms, temps écoulé = 63 ms.
Voici où nous devons prendre une décision. Prenons-nous la victoire d'un 63 ms. mise à jour des statistiques basée sur la partition, ou augmentons-nous encore le taux d'échantillonnage? Disons que nous sommes prêts à prendre le coup initial d'échantillonnage à 50% sur une statistique incrémentale:
- Mise à jour des statistiques incrémentielles à 50%: temps écoulé = 16840 ms.
- Mettre à jour les statistiques incrémentielles, partition 3 avec rééchantillonnage (50% - notre nouveau temps de mise à jour): temps écoulé = 295 ms.
Nous pouvons échantillonner beaucoup plus de données, peut-être configurer l'optimiseur pour mieux deviner nos données (même s'il n'utilise pas encore de statistiques au niveau de la partition) et nous pouvons le faire plus rapidement maintenant que nous avons statistiques incrémentielles.
Une dernière chose amusante à comprendre, cependant. Qu'en est-il des mises à jour synchrones des statistiques? Le taux d'échantillonnage de 50% est-il conservé même lorsque les statistiques automatiques interviennent?
J'ai supprimé des données de la partition 3 et exécuté une requête sur CreationDate et vérifié puis vérifié les taux avec la même requête ci-dessous. Le taux d'échantillonnage de 50% a été conservé.
Donc, histoire courte: les statistiques incrémentales peuvent être un outil utile avec la bonne quantité de réflexion et de travail de configuration initiale. Cependant, vous devez connaître le problème que vous essayez de résoudre, puis vous devez le résoudre de manière appropriée. Si vous obtenez de mauvaises estimations de cardinalité, vous pourriez être en mesure d'obtenir de meilleurs plans avec un taux d'échantillonnage stratégique et une intervention investie. Cependant, vous n'obtenez qu'une petite partie des avantages puisque l'histogramme utilisé est la seule page de statistiques fusionnée et non les informations au niveau de la partition. Si vous ressentez de la douleur dans votre fenêtre de maintenance, des statistiques incrémentielles peuvent peut-être vous aider, mais elles nécessiteront probablement la mise en place d'un processus d'intervention de maintenance hautement tactile. Indépendamment,:
- Statistiques créées avec des index qui ne sont pas alignés sur la partition avec la table de base.
- Statistiques créées sur des bases de données secondaires lisibles AlwaysOn.
- Statistiques créées sur des bases de données en lecture seule.
- Statistiques créées sur des index filtrés.
- Statistiques créées sur les vues.
- Statistiques créées sur des tables internes.
- Statistiques créées avec des index spatiaux ou des index XML.
J'espère que cela t'aides
select
sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
leading_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
parition_number = isnull(sp.partition_number,1),
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter = coalesce(sp.modification_counter, n1.modification_counter)
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
cross apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) sp
outer apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) n1
where n1.node_id = 1
and (
(is_incremental = 0)
or
(is_incremental = 1 and sp.partition_number is not null)
)
and t.name = 'Posts'
and s.name like 'st_posts%'
order by s.stats_id,isnull(sp.partition_number,1)