Problème clé croissant - Colonne de tête intitulée «Stationnaire» - SQL Server

9

J'ai fait des recherches sur des requêtes à exécution lente dans notre base de données et j'ai conclu qu'il s'agit d'un problème clé croissant classique. Comme de nouvelles lignes sont insérées presque constamment, et qu'un morceau de SQL donné pour extraire les dernières données de la base de données s'exécute toutes les 30 minutes, la première option de mise à jour des statistiques toutes les 30 minutes semblait être un gaspillage de ressources.

J'ai donc examiné le drapeau de trace 2389 qui devrait en principe aider, mais cela nécessite que la colonne principale soit marquée comme ascendante, et lorsque j'ai utilisé le drapeau de trace 2388 pour vérifier les statistiques d'index (PK), je vois que la colonne principale est en fait marqué comme stationnaire - comme c'est le cas pour plusieurs des index PK sur d'autres tables mis à jour en même temps.

entrez la description de l'image ici

Il ne semble pas y avoir beaucoup d'indications sur les résultats d'une image de marque de stationnaire, mais j'ai trouvé KB2952101 qui dit que si moins de 90% des inserts étaient supérieurs à l'ancienne valeur maximale, il serait classé comme stationnaire. Toutes nos insertions sont de nouvelles soumissions, et la colonne de tête est une colonne bigint IDENTITY, donc 100% des insertions doivent être supérieures à la valeur précédente maximale.

Donc, ma question est pourquoi la colonne serait-elle marquée comme stationnaire, alors qu'elle est évidemment ascendante?

Une tentative antérieure de résoudre ce problème pour certains SQL exécutés quotidiennement (qui fonctionnait très bien) a entraîné la configuration d'un travail pour mettre à jour les statistiques de cette table tous les soirs. La mise à jour ne fait pas un FULLSCAN, alors est-ce que le scan échantillonné manque parfois les nouvelles lignes, donc il ne s'affiche pas toujours comme croissant?

La seule autre chose à laquelle je peux penser qui pourrait affecter cela, c'est que nous avons un travail d'archivage exécuté en arrière-plan pour supprimer des lignes au-delà d'un certain âge. Cela pourrait-il avoir un effet sur la marque?

Le serveur est SQL Server 2012 SP1.

Mise à jour : un autre jour, une autre mise à jour des statistiques - même marque stationnaire. Il y a eu 28049 nouvelles insertions depuis la précédente mise à jour des statistiques. Chaque ligne a un horodatage du moment où elle a été insérée, donc si je sélectionne max (id) dans la table où l'horodatage <'20161102' j'obtiens 23313455 De même, si je fais cela pour quand les statistiques ont été mises à jour aujourd'hui, j'obtiens 23341504.

La différence entre ceux-ci est les 28049 nouveaux inserts, donc comme vous pouvez le voir, tous les nouveaux inserts ont reçu de nouvelles clés ascendantes (comme prévu), suggérant que la colonne de tête devrait être marquée comme ascendante plutôt que stationnaire.

Au cours de la même période, notre travail d'archivage a supprimé 213 629 lignes (nous effaçons lentement les anciennes données). Y a-t-il une chance qu'un nombre de lignes réduit puisse contribuer à la marque stationnaire? J'ai déjà testé cela auparavant et il ne semblait pas que cela fasse de différence.

Mise à jour 2 : Un autre jour, une autre mise à jour des statistiques, et la colonne est désormais signalée comme Ascendant! Conformément à la théorie sur les suppressions affectant cela, j'ai vérifié le pourcentage de mises à jour insérées par rapport aux suppressions, et hier 13% étaient des insertions, tandis que les insertions des deux jours précédents représentaient environ 12%. Je ne pense pas que cela nous donne quoi que ce soit de concluant.

Fait intéressant, une table associée qui obtient en moyenne 4 lignes insérées pour chaque ligne insérée dans cette table principale, et dont les statistiques sont mises à jour en même temps, a sa colonne IDENTITY PK toujours stationnaire!?

Mise à jour 3 : Au cours du week-end, nous recevons plus d'inserts. Ce matin, la colonne principale est de retour à Stationary. Lors de la dernière mise à jour des statistiques, nous avions 46840 insertions et seulement 34776 suppressions.

Encore une fois, il est intéressant de noter que le tableau connexe que j'ai mentionné ci-dessus a maintenant sa première colonne marquée Ascending. N'y a-t-il pas de documentation pouvant expliquer cela?

Mise à jour 4 : cela fait environ une semaine maintenant, le travail d'archivage a effacé l'arriéré, nous supprimons donc constamment environ les deux tiers du nombre de lignes insérées. Les statistiques montrent des résultats mitigés dans les tableaux associés, l'un indiquant les valeurs stationnaires et les deux les valeurs ascendantes, bien qu'elles soient toutes mises à jour de manière similaire.

Nik
la source
Dans notre cas, toutes les insertions ont des valeurs qui sont au-delà de la valeur la plus élevée de l'histogramme, donc la colonne ne doit pas être marquée Stationnaire, donc je n'ai pas essayé le drapeau. C'est une explication de la raison pour laquelle SQL Server semble marquer au hasard les colonnes que je recherche vraiment. Merci.
Nik

Réponses:

3

Il ne semble pas y avoir beaucoup d'indications sur les résultats d'une image de marque de stationnaire, mais j'ai trouvé KB2952101 qui dit que si moins de 90% des inserts étaient supérieurs à l'ancienne valeur maximale, il serait classé comme stationnaire. Tous nos encarts sont de nouvelles soumissions, et la colonne de tête est une colonne bigint IDENTITY, donc 100% des encarts doivent être supérieurs à la valeur précédente maximale.

Donc, ma question est pourquoi la colonne serait-elle marquée comme stationnaire, alors qu'elle est évidemment ascendante?

Il sera marqué stationnaire si, comme vous l'avez déjà dit, 10% ou plus des inserts ne sont pas ascendants. Si 100% de vos insertions étaient comme vous le dites ... alors vous pourriez ne pas avoir ce problème, jusqu'à ce que vous les supprimiez bien sûr, mais il redeviendrait inconnu.

Voici une repro de votre problème:

use master;
go
-- create a database for this to test
create database AscendingKey;
go

use AscendingKey;
go
-- create a test table
create table dbo.AscendingKeyTableTest
(
    SomeData        char(100) default('A'),
    AscendingKey    bigint not null,
);
go

-- insert some dummy data
set nocount on
go

declare @i int = 1

while(@i <= 1000)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- create stats on the ascendingkey column
create statistics AscendingKeyStats on dbo.AscendingKeyTableTest(AscendingKey);
go

-- look at the stats
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- ascending!
-- we hit the 3x stats updates to have it 'learn'

-- what happens if we insert more than 10% that isn't ascending
declare @i int = 1;

while(@i <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- still says ascending... but...
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- what if we update again?
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go
-- stationary
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- get it back to ascending
declare @i int;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+1);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+2);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+3);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go

-- what about the deletes?
delete from AscendingKeyTableTest where AscendingKey % 3 = 0
go

update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- back to unknown

-- cleanup
use master
go

drop database AscendingKey
go
Sean Gallardy - Utilisateur retraité
la source
J'ai fait un test rapide en utilisant le même script que ci-dessus, mais j'ai uniquement exécuté les parties d'insertion et de suppression. Il semble que si vous supprimez un nombre de lignes beaucoup plus important que celui inséré, il redeviendra stationnaire (encore environ 10%). Dans vos données mises à jour, vous avez inséré environ 10% de toutes les modifications de données apportées - il semble que les suppressions vous causent du chagrin. À ce stade, je suggère de laisser l'objet stats frapper ascendant, puis de le geler en ne le mettant pas à jour.
Sean Gallardy - Utilisateur retraité
J'ai essayé de recréer ce que vous aviez fait et j'ai fini par ajouter 10 lignes supplémentaires et en supprimer 1000, en mettant à jour les statistiques, puis en affichant les statistiques, et cela apparaît toujours comme croissant: insertions depuis la dernière mise à jour: 10, suppressions depuis la dernière mise à jour: 1000, type de colonne principale : Ascendant. Vous ne savez pas pourquoi j'obtiens un résultat différent pour vous? Si vos résultats sont corrects, il pourrait simplement s'agir de mettre en place des résultats moins qu'optimaux maintenant, puis lorsque notre arriéré d'archivage a disparu, essayez à nouveau.
Nik
0

À mon avis, à moins que vous ne génériez la colonne clé principale sur le serveur lui-même, vous pouvez entrer dans de petits nids de poule en vous basant sur sa génération sur des clients individuels.

Avez-vous également essayé Trace Flag 2371.

TF 2371 est documenté ici .

La base de connaissances est intitulée «Contrôle du comportement d'Autostat (AUTO_UPDATE_STATISTICS) dans SQL Server». et la base de connaissances est 2754171.

Il serait très utile que vous nous donniez la liste des impacts réels des nouvelles données qui ne parviennent pas à temps dans les statistiques.

Des index erronés ont été choisis. Et, dans l'affirmative, pouvez-vous nous énumérer les index et leurs clés primaires?

Pouvez-vous également partager les plans générés lorsque les statistiques sont datées et en temps opportun. Je voudrais comparer les deux.

Je pense que les décisions de SQL Cost Based Optimizer (Rules and Costing) sont assez bonnes; en dehors des zones ésotériques comme celle-ci.

S'il s'agit d'un cas spécial, des explications supplémentaires peuvent être utiles et justifier l'ouverture d'un élément Connect.

Soit dit en passant, à mon humble avis, vous aurez plus d'avantages globaux à ce que le fournisseur utilise SP que SQL ad-hoc.

Daniel Adeniji
la source
Merci, les ID sont tous créés par SQL Server. Je comprends que le drapeau 2371 rend les mises à jour des statistiques plus fréquentes. À en juger par la table sur brentozar.com/archive/2016/03/… , la taille de notre table ( 14 millions de lignes) et le nombre d'insertions quotidiennes (28 000 lignes), les statistiques ne seraient toujours mises à jour que tous les 4 jours environ, donc l'extrait de nouvelles données ne sera la plupart du temps pas au courant des nouvelles données. Les requêtes que j'ai examinées ne sont pas un problème, c'est de comprendre comment SQL Server marque la première colonne que j'aimerais connaître. Merci encore.
Nik