Database
 sql >> Datenbank >  >> RDS >> Database

Trace Flag 2389 und der neue Kardinalitätsschätzer

Eines der Trace-Flags von SQL Server, das es schon seit einiger Zeit gibt, ist 2389. Es wird oft mit 2390 diskutiert, aber ich möchte mich in diesem Beitrag nur auf 2389 konzentrieren. Das Trace-Flag wurde in SQL Server 2005 SP1 eingeführt, das am 18. April 2006 veröffentlicht wurde (laut http://sqlserverbuilds.blogspot.co.uk/), es gibt es also seit über 10 Jahren. Trace-Flags ändern das Verhalten der Engine, und 2389 ermöglicht es dem Optimierer, Statistiken zu identifizieren, die aufsteigend sind, und sie als solche zu kennzeichnen (oft als "Problem mit aufsteigenden Schlüsseln" bezeichnet). Wenn dies auftritt, werden die Statistiken automatisch zur Kompilierzeit der Abfrage aktualisiert, was bedeutet, dass der Optimierer Informationen über den höchsten Wert in der Tabelle hat (im Vergleich dazu, wenn das Trace-Flag nicht verwendet wird).

Ich hatte kürzlich eine Diskussion mit einem Kunden über die Verwendung dieses Ablaufverfolgungsflags, und es kam aufgrund dieses Szenarios auf:

  • Sie haben eine große Tabelle mit INT als Primärschlüssel, die geclustert ist.
  • Sie haben einen nicht gruppierten Index, der auf eine DATETIME-Spalte führt.
  • Die Tabelle enthält ungefähr 20 Millionen Zeilen, und jeden Tag werden zwischen 5.000 und 100.000 Zeilen hinzugefügt.
  • Statistiken werden im Rahmen Ihrer Wartungsaufgabe jede Nacht aktualisiert.
  • Statistiken für die automatische Aktualisierung sind für die Datenbank aktiviert, aber selbst wenn 100.000 Zeilen zur Tabelle hinzugefügt werden, sind das weit weniger als die 4 Millionen Zeilen (20 %), die zum Aufrufen einer automatischen Aktualisierung erforderlich sind.
  • Wenn Benutzer die Tabelle mit dem Datum im Prädikat abfragen, kann die Abfrageleistung großartig oder schrecklich sein.

Diese letzte Kugel lässt es fast wie ein Problem mit der Parameterempfindlichkeit klingen, ist es aber nicht. In diesem Fall handelt es sich um ein Statistikproblem. Mein Vorschlag an den Kunden war, TF 2389 zu verwenden oder die Statistiken im Laufe des Tages häufiger zu aktualisieren (z. B. über einen Agentenjob). Dann dachte ich, ich mache ein paar Tests, da der Client SQL Server 2014 ausführte. Hier wurde es interessant.

Die Einrichtung

Wir werden die oben genannte Tabelle zum Testen im RTM-Build von SQL Server 2016 in der WideWorldImporters-Datenbank erstellen, und ich werde den Kompatibilitätsmodus anfänglich auf 110 setzen:

USE [master];GORESTORE DATABASE [WideWorldImporters]FROM  DISK =N'C:\Backups\WideWorldImporters-Full.bak'WITH  FILE =1,MOVE N'WWI_Primary' TO N'C:\Databases\WideWorldImporters\WideWorldImporters .mdf',MOVE N'WWI_UserData' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',MOVE N'WWI_Log' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.ldf',MOVE N'WWI_InMemory_Data_1' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_InMemory_Data_1',NOUNLOAD, REPLACE, STATS =5;GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =110;GO USE [WideWorldImporters];GO CREATE TABLE [Sales].[BigOrders]([OrderID ] [int] NOT NULL,[CustomerID] [int] NOT NULL,[SalespersonID] [int] NOT NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NOT NULL,[BackorderOrderID] [int] NULL, [Bestelldatum] [Datum] NOT NULL,[ExpectedDeliveryDate] [date] NOT NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUndersupplyBackordered] [bit] NOT NULL,[Comments] [nvarchar ](max) NULL,[DeliveryInstructions] [nvarchar](max) NULL,[InternalComments] [nvarchar](max) NULL,[PickingCompletedWhen] [datetime2](7) NULL,[LastEditedBy] [int] NOT NULL,[LastEditedWhen ] [datetime2](7) NOT NULL,CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED([OrderID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [USERDATA]) ON [BENUTZERDATEN] TEXTIMAGE_ON [BENUTZERDATEN];

Als Nächstes laden wir etwa 24 Millionen Zeilen in BigOrders und erstellen einen Nonclustered-Index für OrderDate.

SET NOCOUNT ON; DECLARE @Loops SMALLINT =0, @IDIncrement INT =75000; WHILE @Loops <325 – Passen Sie dies an, um die Anzahl der hinzugefügten Zeilen zu erhöhen oder zu verringern. [OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + @IDIncrement,[CustomerID ],[VerkäuferPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy],[LastEditedWhen]FROM [Verkäufe].[Bestellungen]; KONTROLLPUNKT; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END CREATE NOCLLUSTERED INDEX [NCI_BigOrders_OrderDate]ON [Sales].[BigOrders] ([OrderDate], CustomerID);

Wenn wir das Histogramm für den Nonclustered-Index überprüfen, sehen wir, dass das höchste Datum 2016-05-31 ist:

DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);


Statistiken für das NCI am OrderDate

Wenn wir nach einem Datum darüber hinaus suchen, notieren Sie die geschätzte Anzahl der Zeilen:

WÄHLEN Sie CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01';


Planen Sie die Abfrage nach einem Datum, das über das Histogramm hinausgeht

Es ist 1, weil der Wert außerhalb des Histogramms liegt. Und in diesem Fall ist das in Ordnung, da die Tabelle keine Zeilen nach dem 31. Mai 2016 enthält. Aber fügen wir einige hinzu und führen dann dieselbe Abfrage erneut aus:

INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Kommentare],[Lieferanweisungen],[InterneKommentare],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-01',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales] .[Bestellungen];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01';


Planen Sie nach dem Hinzufügen von Zeilen nach dem 31. Mai

Die geschätzte Anzahl der Zeilen ist immer noch 1. Aber hier wird es interessant. Lassen Sie uns den Kompatibilitätsmodus auf 130 ändern, damit wir den neuen Kardinalitätsschätzer verwenden, und sehen, was passiert.

USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =130GO USE [WideWorldImporters];GO SELECT CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01'; 


Planen Sie nach dem Hinzufügen von Zeilen für den 1. Juni mit dem neuen CE

Unsere Planform ist dieselbe, aber jetzt beträgt unsere Schätzung 4.898 Zeilen. Das neue CE behandelt Werte außerhalb der Historie anders als das alte CE. Brauchen wir also überhaupt das Trace-Flag 2389?

Der Test – Teil I

Für den ersten Test bleiben wir im Kompatibilitätsmodus 110 und führen durch, was wir mit 2389 sehen würden. Wenn Sie dieses Ablaufverfolgungsflag verwenden, können Sie es entweder als Startparameter im SQL Server-Dienst aktivieren oder DBCC verwenden TRACEON, um es instanzweit zu aktivieren. Beachten Sie, dass in Ihrer Produktionsumgebung, wenn Sie DBCC TRACEON verwenden, um das Trace-Flag zu aktivieren, das Trace-Flag nicht wirksam ist, wenn die Instanz neu gestartet wird.

Wenn das Trace-Flag aktiviert ist, muss eine Statistik drei (3) Mal aktualisiert werden, bevor der Optimierer sie als aufsteigend kennzeichnet. Wir erzwingen aus Sicherheitsgründen vier Aktualisierungen und fügen zwischen jeder Aktualisierung weitere Zeilen hinzu.

USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =110;GO DBCC TRACEON (2389, -1);GO USE [WideWorldImporters];GO UPDATE STATISTICS [Verkäufe].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[ Kommentare],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25100000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], '2016-06-02',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders ];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID ],[VerkäuferPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy][LastEditedWhen])SELECT[OrderID] + 25200000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-03',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber], [IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate]; GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Kommentare],[Lieferanweisungen],[InterneKommentare],[PickingCompletedWhen],[LastEditedBy] ,[LastEditedWhen])SELECT[OrderID] + 25300000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-04',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate]; 

Wenn wir die Statistik erneut überprüfen und das Trace-Flag 2388 verwenden, um zusätzliche Informationen anzuzeigen, sehen wir, dass die Statistik jetzt als Ascending:

gekennzeichnet ist
DBCC TRACEON (2388);GO DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);


NCI am Bestelldatum als ASC gekennzeichnet

Wenn wir nach einem Datum in der Zukunft fragen und die Statistiken vollständig aktuell sind, sehen wir, dass immer noch 1 Zeile geschätzt wird:

WÄHLEN Sie CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';


Plan nach Aktivierung von TF 2389, aber keine Zeilen jenseits des Histogramms

Jetzt fügen wir Zeilen für den 5. Juni hinzu und führen dieselbe Abfrage erneut aus:

INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Kommentare],[Lieferanweisungen],[InterneKommentare],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25400000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-05',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales] .[Bestellungen];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';


Plan nach Aktivierung von TF 2389, mehr als 70.000 Zeilen über Histogramm hinaus hinzugefügt

Unsere Schätzung ist nicht mehr 1, sondern 22.595. Lassen Sie uns jetzt nur zum Spaß das Trace-Flag deaktivieren und sehen, wie die Schätzung lautet (ich werde den Prozedur-Cache löschen, da das Deaktivieren des Trace-Flags keinen Einfluss darauf hat, was sich derzeit im Cache befindet).

DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';


Planen, nachdem TF 2389 *deaktiviert* wurde, mehr als 70.000 Zeilen hinzugefügt Histogramm

Diesmal bekomme ich wieder eine Schätzung von 1 Reihe. Obwohl die Statistik als aufsteigend gekennzeichnet ist, wird bei nicht aktiviertem Trace-Flag 2389 nur eine Zeile geschätzt, wenn Sie einen Wert außerhalb des Histogramms abfragen.

Wir haben gezeigt, dass das Ablaufverfolgungsflag 2389 das tut, was wir erwarten – was es immer getan hat – wenn der alte Kardinalitätsschätzer verwendet wird. Mal sehen, was mit dem neuen passiert.

Der Test – Teil II

Um gründlich zu sein, werde ich alles zurücksetzen. Ich werde die Datenbank erneut erstellen, den Kompatibilitätsmodus auf 130 setzen, die Daten anfänglich laden, dann das Trace-Flag 2389 aktivieren und drei Datensätze mit dazwischen liegenden Statistikaktualisierungen laden.

USE [master];GO RESTORE DATABASE [WideWorldImporters]FROM  DISK =N'C:\Backups\WideWorldImporters-Full.bak'WITH  FILE =1,MOVE N'WWI_Primary' TO N'C:\Databases\WideWorldImporters\ WideWorldImporters.mdf',MOVE N'WWI_UserData' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',MOVE N'WWI_Log' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.ldf',MOVE N'WWI_InMemory_Data_1' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_InMemory_Data_1',NOUNLOAD, REPLACE, STATS =5;GO USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =130;GO USE [WideWorldImporters];GO CREATE TABLE [Verkäufe] .[BigOrders]([OrderID] [int] NOT NULL,[CustomerID] [int] NOT NULL,[SalespersonPersonID] [int] NOT NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NOT NULL,[ BackorderOrderID] [int] NULL,[OrderDate] [date] NOT NULL,[ExpectedDeliveryDate] [date] NOT NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUndersupplyBackordered] [bit] NOT NULL,[Co mments] [nvarchar](max) NULL,[DeliveryInstructions] [nvarchar](max) NULL,[InternalComments] [nvarchar](max) NULL,[PickingCompletedWhen] [datetime2](7) NULL,[LastEditedBy] [int] NOT NULL,[LastEditedWhen] [datetime2](7) NOT NULL,CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED([OrderID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [USERDATA]) ON [USERDATA] TEXTIMAGE_ON [USERDATA];GO SET NOCOUNT ON; DECLARE @Loops SMALLINT =0;DECLARE @IDIncrement INT =75000; WHILE @Loops <325 – Passen Sie dies an, um die Anzahl der hinzugefügten Zeilen zu erhöhen oder zu verringern. [OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + @IDIncrement,[CustomerID ],[VerkäuferPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy],[LastEditedWhen]FROM [Verkäufe].[Bestellungen]; KONTROLLPUNKT; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END CREATE NOCLLUSTERED INDEX [NCI_BigOrders_OrderDate]ON [Sales].[BigOrders] ([OrderDate], CustomerID);GO INSERT [Sales].[BigOrders] ([Bestell-ID],[Kunden-ID],[Vertriebsmitarbeiter-ID],[PickedByPersonID],[Kontaktperson-ID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[ InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-01', [ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO DBCC TRACEON (2389, -1);GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[Salesperson PersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy] ,[LastEditedWhen])SELECT[OrderID] + 25100000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-02',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments ],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedW hen])SELECT[OrderID] + 25200000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-03',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales ].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments], [DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25300000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016- 06-04',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalCo mments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];

Ok, unsere Daten sind also vollständig geladen. Wenn wir die Statistik erneut überprüfen und das Trace-Flag 2388 verwenden, um zusätzliche Informationen anzuzeigen, sehen wir, dass die Statistik wieder als Ascending:

gekennzeichnet ist
DBCC TRACEON (2388);GO DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);


NCI OrderDate-Statistik markiert als ASC mit TF 2389 und Kompatibilitätsmodus 130

Ok, fragen wir also noch einmal nach dem 5. Juni:

WÄHLEN Sie CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';


Planen Sie mit neuem CE, keine Zeilen über das hinaus, was im Histogramm angezeigt wird

Unsere Schätzung ist 4.922. Nicht ganz so wie in unserem ersten Test, aber definitiv nicht 1. Jetzt fügen wir einige Zeilen für den 5. Juni hinzu und fragen erneut ab:

INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Kommentare],[Lieferanweisungen],[InterneKommentare],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25400000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-05',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales] .[Bestellungen];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';


Planen Sie mit dem neuen CE, mit mehr als 70.000 Zeilen über dem, was im Histogramm angezeigt wird

Die Schätzung ist die gleiche. Was passiert nun, wenn wir das Trace-Flag 2389 deaktivieren?

DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';


Planen Sie mit neuem CE, aber TF 2389 ist NICHT aktiviert, mit 70K+ Zeilen jenseits des Histogramms

Die Schätzung änderte sich leicht auf 4.930, aber sie änderte sich. Dies sagt mir, dass das Trace-Flag 2389 einen gewissen Einfluss auf die Schätzung hat, aber wie viel ist unbekannt.

Der Test – Teil III

Ich habe einen letzten Test durchgeführt, bei dem ich die Datenbank wiederhergestellt, den Kompatibilitätsmodus auf 130 gesetzt, alle Daten erneut geladen, die Statistiken mehrmals aktualisiert, aber das Trace-Flag 2389 NICHT aktiviert habe. Der Code ist derselbe wie in Teil II, mit Ausnahme der Verwendung DBCC TRACEON, um 2389 zu aktivieren.  Als ich sowohl vor als auch nach dem Hinzufügen der Daten nach dem 5. Juni abgefragt habe, betrug die geschätzte Anzahl an Zeilen 4.920.

Was bedeutet das?

Zusammenfassend lässt sich sagen, dass das Ablaufverfolgungsflag 2389 bei Verwendung des Kompatibilitätsmodus 110 oder niedriger wie immer funktioniert. Bei Verwendung des Kompatibilitätsmodus 120 oder höher und damit des neuen CE sind die Schätzungen jedoch nicht sind im Vergleich zum alten CE identisch und unterscheiden sich in diesem speziellen Fall nicht so sehr, ob das Trace-Flag verwendet wird oder nicht.

Was sollten Sie also tun? Wie immer testen. Ich habe in MSDN nichts Dokumentiertes gefunden, das besagt, dass das Ablaufverfolgungsflag 2389 mit dem Kompatibilitätsmodus 120 und höher nicht unterstützt wird, und ich habe auch nichts gefunden, das eine Verhaltensänderung dokumentiert. Ich finde es sehr interessant, dass die Schätzungen mit dem neuen CE anders (in diesem Fall viel niedriger) sind. Das könnte möglicherweise ein Problem sein, aber bei Schätzungen spielen mehrere Faktoren eine Rolle, und dies war eine sehr einfache Abfrage (eine Tabelle, ein Prädikat). In diesem Fall liegt die Schätzung weit daneben (4.920 Zeilen gegenüber den 22.595 Zeilen für das Datum vom 5. Juni).

Wenn ich die Abfrage für ein Datum erneut ausführe, das die gleiche Anzahl von Zeilen hat, die ist im Histogramm erhalte ich einen ähnlichen Plan, der aber parallel läuft:

WÄHLEN Sie CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-02';


Planen Sie eine Abfrage, die ein Datum im Histogramm verwendet (neu CE, kein TF)

Die Schätzung ist auch genauer (68.318). Der Plan ändert sich in diesem Fall nicht wesentlich, aber die Kosten sind offensichtlich höher. Abhängig von der Anzahl der zurückgegebenen Zeilen könnte dies irgendwann zu einem Tabellenscan führen.

Die beste Anleitung zu diesem Zeitpunkt, wenn Sie 2014 oder höher und den Kompatibilitätsmodus 120 oder höher verwenden und führende Spalten in Statistiken haben, die aufsteigend sind, ist zu testen. Wenn Sie feststellen, dass der neue Kardinalitätsschätzer keine so gute Schätzung liefert wie der alte CE, dann würde ich empfehlen, einen Connect-Eintrag einzureichen, damit das Produktteam darüber informiert ist. Es gibt immer einmalige und einzigartige Fälle, aber wenn viele Kunden (sprich:SIE) immer wieder das gleiche Verhalten feststellen – und es nicht ideal ist – dann ist es wichtig, das Entwicklungsteam darüber zu informieren.

Dies ist ein weiterer wichtiger Punkt, der bei einem Upgrade auf 2014 oder 2016 zu berücksichtigen ist – und eine Erinnerung daran, nicht vernachlässigen Sie Ihre Tests (und übrigens, Query Store wäre hier mit 2016 äußerst nützlich). Ran an die Freunde.