Aufsteigendes Schlüsselproblem - Führende Spalte mit der Bezeichnung "Stationär" - SQL Server

8

Ich habe langsam laufende Abfragen in unserer Datenbank untersucht und bin zu dem Schluss gekommen, dass dies ein klassisches Problem mit aufsteigendem Schlüssel ist. Da fast ständig neue Zeilen eingefügt werden und ein bestimmtes SQL-Element zum Abrufen der neuesten Daten aus der Datenbank alle 30 Minuten ausgeführt wird, schien die erste Option, Statistiken alle 30 Minuten zu aktualisieren, eine Verschwendung von Ressourcen zu sein.

Also habe ich mir Trace Trace 2389 angesehen, was im Prinzip hilfreich sein sollte. Dazu muss jedoch die führende Spalte als aufsteigend gekennzeichnet sein. Wenn ich Trace Flag 2388 zum Überprüfen der (PK) -Indexstatistiken verwendet habe, sehe ich, dass die führende Spalte tatsächlich ist als stationär gekennzeichnet - wie es für mehrere der PK-Indizes in anderen Tabellen gilt, die gleichzeitig aktualisiert werden.

Geben Sie hier die Bildbeschreibung ein

Es scheint nicht viele Hinweise zu geben, was zu einem Branding von Stationary führt. Ich habe jedoch KB2952101 gefunden , das besagt, dass weniger als 90% der Einsätze größer als der alte Maximalwert sind und als Stationary eingestuft werden. Alle unsere Einfügungen sind neue Einreichungen, und die führende Spalte ist eine große IDENTITY-Spalte. Daher sollten 100% der Einfügungen größer sein als der maximale vorherige Wert.

Meine Frage ist also, warum die Spalte als stationär gekennzeichnet wird, wenn sie offensichtlich aufsteigend ist.

Ein früherer Versuch, dieses Problem für täglich laufendes SQL zu beheben (was sehr gut funktionierte), führte dazu, dass ein Job eingerichtet wurde, um die Statistiken für diese Tabelle jede Nacht zu aktualisieren. Das Update führt keinen FULLSCAN durch. Könnte es also sein, dass dem abgetasteten Scan manchmal die neuen Zeilen fehlen, sodass sie nicht immer als aufsteigend angezeigt werden?

Das einzige andere, was ich mir vorstellen kann, ist, dass hinter den Kulissen ein Archivierungsjob ausgeführt wird, der Zeilen ab einem bestimmten Alter löscht. Könnte sich dies auf das Branding auswirken?

Der Server ist SQL Server 2012 SP1.

Update : Ein neuer Tag, ein neues Statistik-Update - dasselbe stationäre Branding. Seit dem letzten Statistik-Update wurden 28049 neue Einfügungen vorgenommen. Jede Zeile hat einen Zeitstempel, wann sie eingefügt wurde. Wenn ich also max (id) aus der Tabelle auswähle, in der der Zeitstempel <'20161102' ist, erhalte ich 23313455. Wenn ich das für die Zeit mache, als die Statistiken heute aktualisiert wurden, erhalte ich 23341504.

Der Unterschied zwischen diesen besteht in den 28049 neuen Einsätzen. Wie Sie sehen können, erhielten alle neuen Einsätze (wie erwartet) neue aufsteigende Schlüssel, was darauf hindeutet, dass die führende Spalte eher als aufsteigend als als stationär gekennzeichnet werden sollte.

Im gleichen Zeitraum löschte unser Archivierungsjob 213.629 Zeilen (wir löschen langsam alte Daten). Gibt es eine Chance, dass eine Reduzierung der Anzahl der Zeilen zum stationären Branding beiträgt? Ich habe das schon einmal getestet und es sah nicht so aus, als hätte es einen Unterschied gemacht.

Update 2 : Ein weiterer Tag, ein weiteres Statistik-Update und die Spalte wird jetzt als aufsteigend markiert! Gemäß der Theorie über Löschungen, die dies beeinflussen, habe ich den Prozentsatz der Aktualisierungen als Einfügungen im Vergleich zu Löschungen überprüft, und gestern waren 13% Einfügungen, während die Einfügungen der letzten zwei Tage etwa 12% ausmachten. Ich denke nicht, dass uns das etwas aussagekräftiges gibt.

Interessanterweise hat eine verwandte Tabelle, die durchschnittlich 4 Zeilen für jede in diese Haupttabelle eingefügte Zeile einfügt und deren Statistiken gleichzeitig aktualisiert werden, ihre IDENTITY PK-Spalte immer noch als stationär!?

Update 3 : Über das Wochenende bekommen wir mehr Beilagen. Heute Morgen ist die führende Kolonne wieder bei Stationary. Beim letzten Statistik-Update hatten wir 46840 Einfügungen und nur 34776 Löschungen.

Interessanterweise hat die verwandte Tabelle, die ich oben erwähnt habe, jetzt die führende Spalte mit der Bezeichnung Aufsteigend. Gibt es keine Dokumentation, die dies erklären kann?

Update 4 : Es ist ungefähr eine Woche her, dass der Archivierungsjob den Rückstand beseitigt hat, sodass wir konsequent etwa zwei Drittel der Anzahl der eingefügten Zeilen löschen. Die Statistiken zeigen gemischte Ergebnisse in den zugehörigen Tabellen, wobei eine stationär und zwei aufsteigend sind, obwohl alle proportional ähnlich aktualisiert wurden.

Nik
quelle
In unserem Fall haben alle Einfügungen Werte, die über dem höchsten Wert im Histogramm liegen. Daher sollte die Spalte nicht als stationär gekennzeichnet werden, daher habe ich das Flag nicht ausprobiert. Dies ist eine Erklärung dafür, warum SQL Server die Spalten, nach denen ich wirklich suche, zufällig zu brandmarken scheint. Vielen Dank.
Nik

Antworten:

3

Es scheint nicht viele Hinweise zu geben, was zu einem Branding von Stationary führt. Ich habe jedoch KB2952101 gefunden, das besagt, dass weniger als 90% der Einsätze größer als der alte Maximalwert sind und als Stationary eingestuft werden. Alle unsere Einfügungen sind neue Einreichungen, und die führende Spalte ist eine große IDENTITY-Spalte. Daher sollten 100% der Einfügungen größer sein als der maximale vorherige Wert.

Meine Frage ist also, warum die Spalte als stationär gekennzeichnet wird, wenn sie offensichtlich aufsteigend ist.

Es wird als stationär eingestuft, wenn, wie Sie bereits festgestellt haben, 10% oder mehr der Einsätze nicht aufsteigend sind. Wenn 100% Ihrer Einfügungen so wären, wie Sie sagen ... dann haben Sie dieses Problem möglicherweise nicht, bis Sie es natürlich löschen, aber dann würde es auf unbekannt zurückgehen.

Hier ist ein Repro Ihres Problems:

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
quelle
Ich habe einen Schnelltest mit demselben Skript wie oben durchgeführt, aber nur das Einfügen und Löschen von Teilen ausgeführt. Es scheint, wenn Sie eine weitaus größere Anzahl von Zeilen löschen als eingefügt, wird sie wieder stationär (wieder etwa 10%). In Ihre aktualisierten Daten haben Sie ungefähr 10% aller vorgenommenen Datenänderungen eingefügt - es scheint, dass die Löschungen Ihnen Kummer bereiten. An dieser Stelle würde ich vorschlagen, das Statistikobjekt aufsteigend treffen zu lassen und es dann einzufrieren, indem es nicht aktualisiert wird.
Sean Gallardy
Ich habe versucht, neu zu erstellen, was Sie getan haben, und am Ende 10 weitere Zeilen hinzugefügt und 1000 gelöscht, Statistiken aktualisiert und dann Statistiken angezeigt. Es wird immer noch aufsteigend angezeigt: Einfügungen seit der letzten Aktualisierung: 10, Löschungen seit der letzten Aktualisierung: 1000, führender Spaltentyp : Aufsteigend. Sie sind sich nicht sicher, warum ich ein anderes Ergebnis für Sie erhalte? Wenn Ihre Ergebnisse korrekt sind, kann es sein, dass Sie jetzt weniger als optimale Ergebnisse erzielen. Wenn sich unser Archivierungsstau aufgelöst hat, versuchen Sie es erneut.
Nik
0

Nach meiner Einschätzung können Sie, wenn Sie nicht die führende Schlüsselspalte auf dem Server selbst generieren, in kleine Schlaglöcher geraten, wenn Sie davon ausgehen, dass sie auf einzelnen Clients generiert wird.

Haben Sie auch Trace Flag 2371 ausprobiert?

TF 2371 ist hier dokumentiert .

Die KB trägt den Titel "Steuern des Autostat-Verhaltens (AUTO_UPDATE_STATISTICS) in SQL Server". und die KB ist 2754171.

Es ist sehr nützlich, wenn Sie für uns die tatsächlichen Auswirkungen der neuen Daten auflisten, die es nicht rechtzeitig in die Statistiken schaffen.

Wurden falsche Indizes ausgewählt? Und wenn ja, können Sie uns bitte die Indizes und ihre Primärschlüssel auflisten?

Können Sie auch die Pläne teilen, die generiert werden, wenn die Statistiken datiert werden, wenn sie aktuell sind? Ich möchte die beiden vergleichen.

Meiner Meinung nach sind die Entscheidungen des SQL Cost Based Optimizer (Regeln und Kosten) recht gut. außerhalb von esoterischen Gebieten wie diesem.

Wenn dies ein Sonderfall ist, kann eine weitere Erklärung hilfreich sein und das Öffnen eines Connect-Elements rechtfertigen.

Abgesehen davon haben Sie meiner bescheidenen Meinung nach insgesamt größere Vorteile, wenn der Anbieter SP verwendet als Ad-hoc-SQL.

Daniel Adeniji
quelle
Vielen Dank, die IDs werden alle von SQL Server erstellt. Ich verstehe, dass Flag 2371 die Statistik-Updates nur häufiger macht. Gemessen an der Tabelle unter brentozar.com/archive/2016/03/… , unserer Tabellengröße ( 14 Millionen Zeilen) und der Anzahl der täglichen Einfügungen (28.000 Zeilen) würden die Statistiken immer noch nur etwa alle 4 Tage aktualisiert Der Extrakt aus neuen Daten kennt die neuen Daten meistens nicht. Die Abfragen, die ich mir angesehen habe, sind kein Problem. Es geht darum zu verstehen, wie SQL Server die führende Spalte markiert, die ich gerne wissen möchte. Danke noch einmal.
Nik