Jedną z flag śledzenia SQL Server, która istnieje już od jakiegoś czasu, jest 2389. Często jest omawiana z 2390, ale w tym poście chcę się skupić tylko na 2389. Flaga śledzenia została wprowadzona w dodatku SP1 dla programu SQL Server 2005, który został wydany 18 kwietnia 2006 r. (według http://sqlserverbuilds.blogspot.co.uk/), więc istnieje od ponad 10 lat. Flagi śledzenia zmieniają zachowanie silnika, a 2389 pozwala optymalizatorowi identyfikować rosnące statystyki i oznaczać je jako takie (często nazywane „problemem z kluczem rosnącym”). W takim przypadku statystyki zostaną automatycznie zaktualizowane w czasie kompilacji zapytania, co oznacza, że optymalizator ma informacje o najwyższej wartości w tabeli (w porównaniu do sytuacji, gdy flaga śledzenia nie jest używana).
Niedawno rozmawiałem z klientem na temat używania tej flagi śledzenia i pojawił się on z powodu tego typu scenariusza:
- Masz dużą tabelę, która ma INT jako klucz podstawowy i jest pogrupowana.
- Masz indeks nieklastrowany, który prowadzi do kolumny DATETIME.
- Tabela zawiera około 20 milionów wierszy i każdego dnia dodawane jest od 5 000 do 100 000 wierszy.
- Statystyki są aktualizowane co noc w ramach zadania konserwacyjnego.
- Statystyki automatycznej aktualizacji są włączone dla bazy danych, ale nawet jeśli do tabeli zostanie dodanych 100 000 wierszy, to mniej niż 4 miliony wierszy (20%) potrzebnych do wywołania automatycznej aktualizacji.
- Gdy użytkownicy wysyłają zapytania do tabeli przy użyciu daty w predykacie, wydajność zapytań może być świetna lub może być okropna.
Ten ostatni punkt prawie sprawia, że brzmi to jak kwestia wrażliwości parametrów, ale tak nie jest. W tym przypadku jest to kwestia statystyki. Moja sugestia dla klienta polegała na używaniu TF 2389 lub częstszym aktualizowaniu statystyk w ciągu dnia (np. za pośrednictwem pracy agenta). Potem pomyślałem, że zrobię trochę testów, ponieważ klient korzystał z SQL Server 2014. Tutaj wszystko stało się interesujące.
Konfiguracja
Zamierzamy stworzyć wspomnianą tabelę do testowania w kompilacji RTM SQL Server 2016, w bazie danych WideWorldImporters i zamierzam początkowo ustawić tryb zgodności na 110:
UŻYJ [master];BAZA DANYCH GORESTORE [WideWorldImporters]Z DYSKU =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_1',MOVE N_WWI_Data 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([BigderOrders]]). ] [int] NOT NULL,[CustomerID] [int] NOT NULL,[SalespersonID] [int] NOT NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NOT NULL,[BackorderID] [int] NULL, [DataZamówienia] [data] NOT NULL,[Oczekiwana data dostawy] [data] NOT NULL,[NumerZamówieniaKlienta] [nvarchar](20) NULL,[IsUnndersupplyBackordered] [bit] NOT NULL,[Komentarze] [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 ON)_USERDATA =ON WŁĄCZONE [DANE UŻYTKOWNIKA] TEXTIMAGE_ON [DANE UŻYTKOWNIKA];
Następnie załadujemy około 24 miliony wierszy do BigOrders i utworzymy indeks nieklastrowy w DataZamówienia.
WŁĄCZ NR; DECLARE @Loops SMALLINT =0, @IDIncrement INT =75000; WHILE @Loops <325 — dostosuj to, aby zwiększyć lub zmniejszyć liczbę dodanych wierszy BEGININSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], [Data zamówienia], [Oczekiwana data dostawy], [Numer zamówienia klienta], [Niedostarczony w zamówieniu wstecznym], [Komentarze], [Instrukcje dostawy], [Komentarze wewnętrzne], [PickingCompletedWhen],[LastEdited By],[LastEditedIncrementID])+SELECT @Customer[Order] ],[IDOsoby Sprzedawcy],[Identyfikator OsobySprzedawcy],[IDOsoby Kontaktu],[IDZamówieniaZamówienia],[DataZamówienia],[Oczekiwana DataDostawy],[Numer Zamówienia Zakupu przez Klienta],[NiedostarczaneZamówienieZamowne],[Komentarze],[Dostarczenie],[Instrukcja],[Instrukcja] [LastEditedBy],[LastEditedWhen]Z [Sprzedaż].[Zamówienia]; PUNKT KONTROLNY; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END UTWÓRZ INDEKS NIECLUSTROWANY [NCI_BigOrders_OrderDate]ON [Sprzedaż].[BigOrders] ([OrderDate], CustomerID);
Jeśli sprawdzimy histogram dla indeksu nieklastrowanego, zobaczymy, że najwyższa data to 31.05.2016:
DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);
Statystyki NCI w dniu zamówienia
Jeśli zapytamy o dowolną datę poza tą datą, zwróć uwagę na szacowaną liczbę wierszy:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sprzedaż].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Zaplanuj podczas zapytania o datę wykraczającą poza histogram
To 1, ponieważ wartość jest poza histogramem. W tym przypadku wszystko jest w porządku, ponieważ w tabeli nie ma wierszy poza 31 maja 2016 r. Dodajmy jednak kilka, a następnie ponownie uruchom to samo zapytanie:
WSTAW [Sprzedaż].[Duże zamówienia]( [Identyfikator zamówienia],[Identyfikator klienta],[Identyfikator osoby sprzedawcy],[Identyfikator osoby kontaktowej],[Identyfikator osoby kontaktowej],[Identyfikator zamówienia zaległego], [Data zamówienia], [Oczekiwana data dostawy], [Numer zamówienia klienta — numer identyfikacyjny zamówienia], ],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[Identyfikator zamówienia] + 25000000,[IDKlienta],[IDOsoby Sprzedawcy],[IDOsoby Wybranej],[IDOsoby Kontaktu], BackorderID],'2016-06-01',[Oczekiwana data dostawy],[Numer zamówienia klienta],[Is UndersupplyBackordered],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompleted When],[Last Edited By]]]FROM [LastEdited] .[Zamówienia];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sprzedaż].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Planuj po dodaniu wierszy po 31 maja
Szacunkowa liczba wierszy to nadal 1. Ale tutaj zaczyna się robić ciekawie. Zmieńmy tryb zgodności na 130, aby użyć nowego narzędzia szacowania kardynacji i zobaczyć, co się stanie.
USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =130GO USE [WideWorldImporters];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sprzedaż].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Plan po dodaniu wierszy na 1 czerwca przy użyciu nowego CE
Nasz kształt planu jest taki sam, ale teraz szacujemy 4898 wierszy. Nowa CE traktuje wartości spoza historii inaczej niż stara CE. Więc… czy potrzebujemy w ogóle flagi śledzenia 2389?
Test – część I
W przypadku pierwszego testu pozostaniemy w trybie zgodności 110 i przeprowadzimy to, co zobaczylibyśmy w przypadku 2389. W przypadku korzystania z tej flagi śledzenia można włączyć ją jako parametr uruchamiania w usłudze SQL Server lub użyć polecenia DBCC TRACEON, aby umożliwić to w całej instancji. Zrozum, że w środowisku produkcyjnym, jeśli użyjesz DBCC TRACEON do włączenia flagi śledzenia, po ponownym uruchomieniu wystąpienia flaga śledzenia nie będzie działać.
Po włączeniu flagi śledzenia statystyka musi zostać zaktualizowana trzy (3) razy, zanim optymalizator oznaczy ją jako rosnącą. Wymusimy cztery aktualizacje w celu uzyskania dobrej oceny i dodamy więcej wierszy między każdą aktualizacją.
USE [master];GO ALTER BAZA DANYCH [WideWorldImporters] SET COMPATIBILITY_LEVEL =110;GO DBCC TRACEON (2389, -1);GO USE [WideWorldImporters];GO UPDATE STATISTICS [Sprzedaż].[BigOrders] [NCI_BigOrders_OrderDate];GO WSTAW [Sprzedaż].[Duże zamówienia]( [Identyfikator zamówienia],[Identyfikator klienta],[Identyfikator osoby sprzedawcy],[Identyfikator osoby kontaktowej],[Identyfikator osoby kontaktowej],[Identyfikator zamówienia zwrotnego],[Data zamówienia],[Oczekiwana data dostawy],[Numer zamówienia klienta],[Identyfikator zamówienia klienta], [Identyfikator zamówienia klienta] Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[IDZamówienia] + 25100000,[IDKlienta],[IDOsoby Sprzedawcy],[Identyfikator Osoby Sprzedawcy],[IDOsoby Kontaktu],[Identyfikator Zamówienia '2016-06-02',[Oczekiwana data dostawy],[Numer zamówienia klienta],[Jest niedostarczony w zamówieniu wstecznym],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[Pobranie zakończone, kiedy], [Ostatnio edytowane przez], [Ostatnio edytowane, kiedy] [Zamówienia] [Sprzedaż] ];GO AKTUALIZUJ STATYSTYKI [Sprzedaż].[DużeZamówienia] [NCI_BigOrders_OrderDate];GO INSERT [Sprzedaż].[DużeZamówienia]( [IDZamówienia],[IDKlienta ],[IDOsoby Sprzedawcy],[Identyfikator OsobySprzedawcy],[IDOsoby Kontaktu],[IDZamówieniaZamówienia],[DataZamówienia],[Oczekiwana DataDostawy],[Numer Zamówienia Zakupu przez Klienta],[NiedostarczaneZamówienieZamowne],[Komentarze],[Dostarczenie],[Instrukcja],[Instrukcja] [LastEditedBy][LastEditedWhen])SELECT[IdentyfikatorZamówienia] + 25200000,[IDKlienta],[Identyfikator OsobySprzedawcy],[Identyfikator OsobyKontaktowej],[IdentyfikatorOsobyKontaktowej],[IdentyfikatorZamówieniaZamówienia],'2016-06-03',[Oczekiwana dataDostawy],[NumerZakupuKlienta],NumerZamówienia [IsUnndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sprzedaż].[Zamówienia];GO UPDATE STATISTICS [Sprzedaż].[Wielkie zamówienia] [NCIder_BigDOrder] GO INSERT [Sprzedaż].[Duże zamówienia]( [IDZamówienia],[IDKlienta],[IDOsoby Sprzedawcy],[Identyfikator OsobyKontaktowej],[IDOsoby Kontaktu],[IDZamówieniaZamówienia],[Data Zamówienia],[Oczekiwana DataDostawy],[NumerZamówieniaZamówienia Klienta],[Identyfikator Zamówienia Klienta] [Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[Pobranie zakończone, gdy],[Ostatnio edytowane przez] ,[LastEditedWhen])SELECT[IDZamówienia] + 25300000,[IDKlienta],[IDOsoby Sprzedawcy],[IdentyfikatorOsobyPickedByPersonID],[IDOsobyKontaktu],[IDZamówieniaZamówienia],'2016-06-04',[Oczekiwana data dostawy],[Numer_zamówienia_zamówienia klienta],[Identyfikator_zamówienia_zamówienia klienta] ],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sprzedaż].[Zamówienia];GO UPDATE STATISTICS [Sprzedaż].[Wielkie zamówienia] [NCI_BigOrders_OrderDate]; pre>Jeśli ponownie sprawdzimy statystyki i użyjemy flagi śledzenia 2388 do wyświetlenia dodatkowych informacji, zobaczymy, że statystyka jest teraz oznaczona jako Rosnąca:
DBCC TRACEON (2388); GO DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);
NCI w dacie zamówienia oznaczony jako ASCJeśli zapytamy o przyszłą datę, gdy statystyki są w pełni aktualne, zobaczymy, że nadal szacujemy 1 wiersz:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plan po włączeniu TF 2389, ale bez wierszy poza histogramemTeraz dodamy wiersze na 5 czerwca i ponownie uruchomimy to samo zapytanie:
WSTAW [Sprzedaż].[Duże zamówienia]( [Identyfikator zamówienia],[Identyfikator klienta],[Identyfikator osoby sprzedawcy],[Identyfikator osoby kontaktowej],[Identyfikator osoby kontaktowej],[Identyfikator zamówienia zaległego], [Data zamówienia], [Oczekiwana data dostawy], [Numer zamówienia klienta — numer identyfikacyjny zamówienia], ],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[IDZamówienia] + 25400000,[IDKlienta],[IDOsoby Sprzedawcy],[IDOsoby Wybranej przez],[,IDOsoby Kontaktu] BackorderIDOrder],'2016-06-05',[Oczekiwana data dostawy],[Numer zamówienia klienta],[Is UndersupplyBackordered],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEdited By]]]FROM [LastEdited] .[Zamówienia];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sprzedaż].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plan po włączeniu TF 2389, ponad 70 000 wierszy dodanych poza histogramNasze oszacowanie nie wynosi już 1, to 22 595. Teraz, dla zabawy, wyłączmy flagę śledzenia i zobaczmy, jakie jest oszacowanie (zamierzam wyczyścić pamięć podręczną procedur, ponieważ wyłączenie flagi śledzenia nie wpłynie na to, co jest obecnie w pamięci podręcznej).
DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT IDKlienta, IDZamówienia, SprzedawcaPersonIDFROM [Sprzedaż].[WielkieZamówienia]WHERE [DataZamówienia] ='2016-06-05';
Plan po *wyłączeniu* TF 2389, ponad 70 000 wierszy dodanych poza histogramTym razem znowu otrzymuję oszacowanie 1 wiersza. Mimo że statystyka jest oznaczona jako rosnąco, jeśli flaga śledzenia 2389 nie jest włączona, szacuje się tylko 1 wiersz podczas zapytania o wartość spoza histogramu.
Wykazaliśmy, że flaga śledzenia 2389 robi to, czego oczekujemy – co zawsze robiła – podczas korzystania ze starego modułu szacowania kardynalizacji. Zobaczmy teraz, co stanie się z nowym.
Test – część II
Aby być dokładnym, zamierzam wszystko zresetować. Ponownie utworzę bazę danych, ustawię tryb zgodności na 130, załaduję dane na początku, a następnie włączę flagę śledzenia 2389 i załaduję trzy zestawy danych z aktualizacjami statystyk pomiędzy nimi.
UŻYJ [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',PRZENIEŚ N'WWI_UserData' DO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',PRZENIEŚ N'WWI_Log' DO N'C:\Bazy danych\WideWorldImporters\WideWorldImporters.ldf_WI_'MOVE 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] TABLE;GO CLESRE .[WielkieZamówienia]([IDZamówienia] [int] NOT NULL,[IDKlienta] [int] NOT NULL,[Identyfikator OsobySprzedawcy] [int] NOT NULL,[PickedByPersonID] [int] NULL,[Identyfikator Osoby Kontaktu] [int] NOT NULL,[ BackorderID] [int] NULL,[OrderDate] [data] NOT NULL,[ExpectedDeliveryDate] [data] NOT NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUnndersupplyBackordered] [bit] NOT NULL,[Co uwagi] [nvarchar](maks.) NULL,[Instrukcje dostawy] [nvarchar](maks.) NULL,[Komentarze wewnętrzne] [nvarchar](maks.) NULL,[PickingCompletedWhen] [datetime2](7) NULL,[LastEditedBy] [int] NIE NULL,[LastEditedWhen] [data i godzina2](7) NOT NULL,CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED([OrderID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_LOCKROW_LOCKS ON_PAGE =ON, [DANE UŻYTKOWNIKA]) WŁ. [DANE UŻYTKOWNIKA] TEXTIMAGE_ON [DANE UŻYTKOWNIKA]; GO SET NOCOUNT WŁ.; DECLARE @Loops SMALLINT =0;DECLARE @IDIncrement INT =75000; WHILE @Loops <325 — dostosuj to, aby zwiększyć lub zmniejszyć liczbę dodanych wierszy BEGININSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], [Data zamówienia], [Oczekiwana data dostawy], [Numer zamówienia klienta], [Niedostarczony w zamówieniu wstecznym], [Komentarze], [Instrukcje dostawy], [Komentarze wewnętrzne], [PickingCompletedWhen],[LastEdited By],[LastEditedIncrementID])+SELECT @Customer[Order] ],[IDOsoby Sprzedawcy],[Identyfikator OsobySprzedawcy],[IDOsoby Kontaktu],[IDZamówieniaZamówienia],[DataZamówienia],[Oczekiwana DataDostawy],[Numer Zamówienia Zakupu przez Klienta],[NiedostarczaneZamówienieZamowne],[Komentarze],[Dostarczenie],[Instrukcja],[Instrukcja] [LastEditedBy],[LastEditedWhen]Z [Sprzedaż].[Zamówienia]; PUNKT KONTROLNY; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END UTWÓRZ INDEKS NIECLUSTROWANY [NCI_BigOrders_OrderDate]ON [Sprzedaż].[BigOrders] ([OrderDate], CustomerID);GO INSERT [Sales].[BigOrders] ( [IDZamówienia],[IDKlienta],[IDOsoby Sprzedawcy],[Identyfikator OsobySprzedawcy],[IDOsoby Kontaktu],[IDZamówieniaZamówienia],[DataZamówienia],[Oczekiwana DataDostawy],[Numer Zamówienia Zakupu przez Klienta],[Zamówienie Niedostarczenia],[Zamówienie],[Komentarz] Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-01', [Oczekiwana data dostawy],[Numer zamówienia zakupu przez klienta],[Zamówiono niedostateczną ilość zamówienia],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]OD [Sprzedaż].[GOCC TRACEON]; -1);GO AKTUALIZUJ STATYSTYKI [Sprzedaż].[Wielkie zamówienia] [NCI_BigOrders_OrderDate];GO INSERT [Sprzedaż].[Wielkie zamówienia]( [IDZamówienia],[IDKlienta],[Sprzedawca PersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[Oczekiwana datadostawy],[CustomerPurchase OrderNumber],[Is UndersupplyBackordered],[Comments],[DeliveryInstrukcje],[edycja],Komentarze [Wewnętrzne odbieranie] ,[LastEditedWhen])SELECT[IDZamówienia] + 25100000,[IDKlienta],[IDOsoby Sprzedawcy],[IDOsobyPickedByPersonID],[IDOsoby Kontaktu],[IDZamówieniaZamówienia],'2016-06-02',[Oczekiwana data dostawy],[Numer_zamówienia_zamówienia klienta],[Identyfikator_zamówienia_zamówienia klienta] ],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sprzedaż].[Zamówienia];GO UPDATE STATISTICS [Sprzedaż].[Wielkie zamówienia] [NCI_BigOrders_GO INSDate]; [Sprzedaż].[Duże zamówienia]( [Identyfikator zamówienia],[Identyfikator klienta],[Identyfikator osoby sprzedawcy],[Identyfikator osoby kontaktowej],[Identyfikator osoby kontaktowej],[Identyfikator zamówienia zwrotnego],[Data zamówienia],[Oczekiwana data dostawy],[Numer zamówienia klienta],[Zamówienie zamówienia] ],[Instrukcje dostawy],[Komentarze wewnętrzne],[Pobranie zakończone, gdy],[Ostatnia edycja przez],[Ostatnia edycjaW kura])SELECT[Identyfikator Zamówienia] + 25200000,[IDKlienta],[IDOsoby Sprzedawcy],[Identyfikator OsobySprzedawcy],[IdentyfikatorOsoby Kontaktu],[IdentyfikatorZamówieniaZamówienia],'2016-06-03',[Oczekiwana dataDostawy],[Numer Zamówienia Zakupu Klienta],[Zamówienie Back-upply] [Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sprzedaż].[Zamówienia];GO UPDATE STATISTICS [Sprzedaż].[Wielkie zamówienia] [NCI_BigOrders_OrderDate];SalesGO INSERT ].[WielkieZamówienia]( [IDZamówienia],[IDKlienta],[IDOsoby Sprzedawcy],[IDOsoby Wybranej PrzezOsobę],[IDOsoby Kontaktu],[IdentyfikatorZamówieniaZamówienia],[Data Zamówienia],[Oczekiwana DataDostawy],[Numer Zamówienia Zakupu Klienta],[Zamówienie Zamówienie],upply [Instrukcje dostawy],[Wewnętrzne komentarze],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[Identyfikator zamówienia] + 25300000,[Identyfikator klienta],[IDOsoby Sprzedawcy],[Identyfikator Osoby Sprzedawcy],[Identyfikator Osoby Kontaktu],[Identyfikator zamówienia-zamówienia 2016] 06-04',[Oczekiwana data dostawy],[Numer zamówienia zakupu przez klienta],[Jest niedostateczna dostawa zaległa],[Komentarze],[Instrukcje dostawy],[Komunikacja wewnętrzna uwagi],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sprzedaż].[Zamówienia];GO UPDATE STATISTICS [Sprzedaż].[WielkieZamówienia] [NCI_BigOrders_OrderDate];Ok, więc nasze dane są w pełni załadowane. Jeśli ponownie sprawdzimy statystyki i użyjemy flagi śledzenia 2388 do wyświetlenia dodatkowych informacji, zobaczymy, że statystyka jest ponownie oznaczona jako Rosnąca:
DBCC TRACEON (2388); GO DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);
Statystyka NCI OrderDate oznaczona jako ASC z TF 2389 i trybem zgodności 130Ok, więc ponownie zapytajmy o 5 czerwca:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plan z nowym CE, bez wierszy poza tym, co jest w histogramieNasze szacunki to 4922. Niezupełnie to, co było w naszym pierwszym teście, ale zdecydowanie nie 1. Teraz dodamy kilka wierszy na 5 czerwca i ponownie zapytamy:
WSTAW [Sprzedaż].[Duże zamówienia]( [Identyfikator zamówienia],[Identyfikator klienta],[Identyfikator osoby sprzedawcy],[Identyfikator osoby kontaktowej],[Identyfikator osoby kontaktowej],[Identyfikator zamówienia zaległego], [Data zamówienia], [Oczekiwana data dostawy], [Numer zamówienia klienta — numer identyfikacyjny zamówienia], ],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[IDZamówienia] + 25400000,[IDKlienta],[IDOsoby Sprzedawcy],[IDOsoby Wybranej przez],[,IDOsoby Kontaktu] BackorderIDOrder],'2016-06-05',[Oczekiwana data dostawy],[Numer zamówienia klienta],[Is UndersupplyBackordered],[Komentarze],[Instrukcje dostawy],[Komentarze wewnętrzne],[PickingCompletedWhen],[LastEdited By]]]FROM [LastEdited] .[Zamówienia];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sprzedaż].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plan z nowym CE, z ponad 70 000 wierszy poza histogramemSzacunek jest taki sam. A teraz, co jeśli wyłączymy flagę śledzenia 2389?
DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT IDKlienta, IDZamówienia, SprzedawcaPersonIDFROM [Sprzedaż].[WielkieZamówienia]WHERE [DataZamówienia] ='2016-06-05';
Plan z nowym CE, ale TF 2389 NIE jest włączony, z ponad 70 tys. wiersze poza tym, co jest na histogramieSzacunek nieznacznie się zmienił, do 4930, ale zmienił się. To mówi mi, że flaga śledzenia 2389 ma pewien wpływ na oszacowanie, ale ile jest nieznane.
Test – część III
Przeprowadziłem jeden końcowy test, w którym przywróciłem bazę danych, ustawiłem tryb zgodności na 130, ponownie załadowałem wszystkie dane, wielokrotnie zaktualizowałem statystyki, ale NIE włączyłem flagi śledzenia 2389. Kod jest taki sam jak w Części II, z wyjątkiem użycia DBCC TRACEON, aby włączyć 2389. Gdy wysyłałem zapytanie dotyczące 5 czerwca, zarówno przed, jak i po dodaniu danych, szacowana liczba wierszy wynosiła 4920.
Co to znaczy?
Podsumowując, podczas korzystania z trybu zgodności 110 lub niższego flaga śledzenia 2389 działa tak, jak zawsze. Ale w przypadku korzystania z trybu zgodności 120 lub wyższego, a tym samym nowego CE, szacunki nie to samo w porównaniu do starego CE, a w tym konkretnym przypadku nie różnią się aż tak bardzo, niezależnie od tego, czy używasz flagi śledzenia, czy nie.
Więc co powinieneś zrobić? Testuj, jak zawsze. Nie znalazłem niczego udokumentowanego w MSDN, który stwierdza, że flaga śledzenia 2389 nie jest obsługiwana w trybie zgodności 120 i wyższym, ani nie znalazłem niczego, co dokumentuje zmianę w zachowaniu. To bardzo interesujące, że szacunki są inne (w tym przypadku znacznie niższe) w przypadku nowej CE. Potencjalnie może to stanowić problem, ale jeśli chodzi o oszacowanie, w grę wchodzi wiele czynników, a było to bardzo proste zapytanie (jedna tabela, jeden predykat). W tym przypadku oszacowanie jest dalekie (4920 wierszy w porównaniu z 22 595 wierszami na dzień 5 czerwca).
Jeśli ponownie uruchomię zapytanie dla daty, która ma taką samą liczbę wierszy, jak jest w histogramie otrzymuję podobny plan, ale działa on równolegle:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sprzedaż].[BigOrders]WHERE [OrderDate] ='2016-06-02';
Zaplanuj zapytanie używające daty w histogramie (nowy CE, bez TF)Szacunek jest również dokładniejszy (68 318). Plan w tym przypadku nie zmienia się znacząco, ale koszt jest oczywiście wyższy. W pewnym momencie, w zależności od liczby wierszy, które zostaną zwrócone, może to spowodować przeskanowanie tabeli.
Najlepszą wskazówką w tej chwili, jeśli korzystasz z wersji 2014 lub nowszej i trybu zgodności 120 lub nowszego, i masz wiodące kolumny w statystykach, które rosną, jest przetestowanie. Jeśli okaże się, że nowy estymator kardynalizacji nie zapewnia tak dobrego oszacowania, jak stara CE, sugerowałbym zgłoszenie elementu Connect, aby zespół produktu był tego świadomy. Zawsze zdarzają się jednorazowe i unikalne przypadki, ale jeśli wielu klientów (czytaj:TY) konsekwentnie znajduje to samo zachowanie – i nie jest to idealne – ważne jest, aby powiadomić o tym zespół programistów.
To kolejny ważny element, który należy wziąć pod uwagę przy aktualizacji do wersji 2014 lub 2016 – i przypomnienie, aby nie zaniedbuj testowanie (a przy okazji, Query Store byłby tutaj niezwykle przydatny w 2016 r.). Dostań się do tego przyjaciele.