Database
 sql >> Baza danych >  >> RDS >> Database

Minimalne logowanie za pomocą INSERT…SELECT do pustych tabel klastrowych

Wprowadzenie

Osiągnięcie minimalnego rejestrowania używając INSERT...SELECT w puste cel indeksu klastrowego nie jest tak prosty, jak opisano w Przewodniku ładowania wydajności danych .

Ten post zawiera nowe szczegóły o wymaganiach minimalnego logowania gdy cel wstawiania jest pustym tradycyjnym indeksem klastrowym. (Słowo „tradycyjny” nie obejmuje sklepu kolumnowego i zoptymalizowane pod kątem pamięci („Hekaton”) tabele w grupach). Aby zapoznać się z warunkami, które mają zastosowanie, gdy tabela docelowa jest stertą, zobacz poprzedni artykuł z tej serii.

Podsumowanie tabel klastrowych

Przewodnik po wydajności ładowania danych zawiera ogólne podsumowanie warunków wymaganych do minimalnego logowania w zgrupowane tabele:

Ten post dotyczy tylko górnego wiersza . Stwierdza, że ​​TABLOCK i ORDER wymagane są wskazówki, z dopiskiem:

Jeśli używasz metody INSERT … SELECT, wskazówka ORDER nie musi być określona, ​​ale wiersze muszą być w tej samej kolejności co indeks klastrowy.

Jeśli używasz BULK INSERT, należy użyć wskazówki dotyczącej zamówienia.

Pusty cel z blokadą tabeli

Górny wiersz podsumowania sugeruje, że wszystkie wstawienia do pustego indeksu klastrowego będą minimalnie rejestrowane tak długo, jak TABLOCK i ORDER podpowiedzi są określone. TABLOCK wskazówka jest wymagana, aby włączyć RowSetBulk obiekt stosowany do ładunków masowych na stercie. ORDER wskazówka jest wymagana, aby wiersze dotarły do ​​wstawki indeksu klastrowanego operator planu w indeksie docelowym kolejność kluczy . Bez tej gwarancji SQL Server może dodawać niepoprawnie posortowane wiersze indeksu, co nie byłoby dobre.

W przeciwieństwie do innych metod ładowania zbiorczego, nie jest to możliwe aby określić wymagane ORDER wskazówka dotycząca INSERT...SELECT oświadczenie. Ta wskazówka to nie to samo jak przy użyciu ORDER BY klauzula INSERT...SELECT oświadczenie. ORDER BY klauzula na INSERT gwarantuje tylko sposób, w jaki każda tożsamość przypisane są wartości, a nie kolejność wstawiania wierszy.

Dla INSERT...SELECT , SQL Server dokonuje własnej decyzji czy upewnić się, że wiersze są prezentowane w wstawce indeksu klastrowego operator w kolejności klucza, czy nie. Wynik tej oceny jest widoczny w planach wykonania poprzez DMLRequestSort właściwość Wstaw operator. DMLRequestSort właściwość musi być ustawione na prawdę dla INSERT...SELECT do indeksu, aby był minimalnie rejestrowany . Gdy jest ustawiony na false , minimalne logowanie nie może wystąpić.

Posiadanie DMLRequestSort ustaw prawdę jest jedyną akceptowaną gwarancją zamawiania wstawiania danych wejściowych dla programu SQL Server. Można sprawdzić plan wykonania i przewidywać że wiersze powinny/będzie/muszą dotrzeć w kolejności indeksów klastrowych, ale bez określonych gwarancji wewnętrznych dostarczone przez DMLRequestSort , ta ocena się nie liczy.

Kiedy DMLRequestSort jest prawda , SQL Server może wprowadź wyraźne sortowanie operatora w planie wykonania. Jeśli może wewnętrznie zagwarantować zamawianie w inny sposób, Sortuj można pominąć. Jeśli dostępne są zarówno alternatywy sortowania, jak i braku sortowania, optymalizator utworzy opartą na kosztach wybór. Analiza kosztów nie uwzględnia minimalnego logowania bezpośrednio; jest napędzany oczekiwanymi korzyściami sekwencyjnego we/wy i unikaniem dzielenia stron.

Warunki DMLRequestSort

Oba poniższe testy muszą przejść, aby SQL Server wybrał ustawienie DMLRequestSort do prawdy podczas wstawiania do pustego indeksu klastrowego z określonym blokowaniem tabeli:

  • Szacunkowe ponad 250 wierszy po stronie wejściowej wstawki z indeksem klastrowym operator; i
  • Szacunkowa rozmiar danych więcej niż 2 strony . Szacowany rozmiar danych nie jest liczbą całkowitą, więc wynik 2.001 stron spełnia ten warunek.

(Może to przypominać o warunkach minimalnego rejestrowania sterty , ale wymagane szacunkowe rozmiar danych to dwie strony zamiast ośmiu).

Obliczanie rozmiaru danych

szacowany rozmiar danych obliczenie tutaj podlega tym samym dziwactwom opisanym w poprzednim artykule dla stosów, z wyjątkiem tego, że 8-bajtowy RID nie jest obecny.

W przypadku SQL Server 2012 i wcześniejszych oznacza to 5 dodatkowych bajtów na wiersz są uwzględniane przy obliczaniu rozmiaru danych:jeden bajt na wewnętrzny bit flaga i cztery bajty dla unikacza (używane w obliczeniach nawet dla unikalnych indeksów, które nie przechowują unikatnika ).

W przypadku SQL Server 2014 i nowszych, uniquifier jest poprawnie pominięty dla unikalny indeksy, ale jeden dodatkowy bajt dla wewnętrznego bitu flaga jest zachowana.

Demo

Poniższy skrypt należy uruchomić na rozwojowej instancji SQL Server w nowej testowej bazie danych ustaw na używanie SIMPLE lub BULK_LOGGED model odzyskiwania.

Demo ładuje 268 wierszy do zupełnie nowej tabeli klastrowej za pomocą INSERT...SELECT z TABLOCK oraz raporty dotyczące wygenerowanych rekordów dziennika transakcji.

IF OBJECT_ID(N'dbo.Test', N'U') IS NOT NULL
BEGIN
    DROP TABLE dbo.Test;
END;
GO
CREATE TABLE dbo.Test 
(
    id integer NOT NULL IDENTITY
        CONSTRAINT [PK dbo.Test (id)]
        PRIMARY KEY,
    c1 integer NOT NULL,
    padding char(45) NOT NULL
        DEFAULT ''
);
GO
-- Clear the log
CHECKPOINT;
GO
-- Insert rows
INSERT dbo.Test WITH (TABLOCK) 
    (c1)
SELECT TOP (268)
    CHECKSUM(NEWID())
FROM master.dbo.spt_values AS SV;
GO
-- Show log entries
SELECT
    FD.Operation,
    FD.Context,
    FD.[Log Record Length],
    FD.[Log Reserve],
    FD.AllocUnitName,
    FD.[Transaction Name],
    FD.[Lock Information],
    FD.[Description]
FROM sys.fn_dblog(NULL, NULL) AS FD;
GO
-- Count the number of  fully-logged rows
SELECT 
    [Fully Logged Rows] = COUNT_BIG(*) 
FROM sys.fn_dblog(NULL, NULL) AS FD
WHERE 
    FD.Operation = N'LOP_INSERT_ROWS'
    AND FD.Context = N'LCX_CLUSTERED'
    AND FD.AllocUnitName = N'dbo.Test.PK dbo.Test (id)';

(Jeśli uruchamiasz skrypt na SQL Server 2012 lub starszym, zmień TOP klauzula w skrypcie od 268 do 252 z powodów, które zostaną wyjaśnione za chwilę.)

Dane wyjściowe pokazują, że wszystkie wstawione wiersze zostały w pełni zarejestrowane pomimo pustego docelowa tabela klastrowa i TABLOCK wskazówka:

Obliczony rozmiar danych wstawiania

Właściwości planu wykonania wstawki z indeksem klastrowym operator pokazuje, że DMLRequestSort jest ustawione na fałsz . Dzieje się tak, ponieważ chociaż szacowana liczba wierszy do wstawienia przekracza 250 (spełnia pierwszy wymóg), obliczona rozmiar danych nie przekraczają dwie strony po 8 KB.

Szczegóły obliczeń (dla SQL Server 2014 i nowsze) są następujące:

  • Łączna stała długość rozmiar kolumny =54 bajty :
    • Identyfikator typu 104 bit =1 bajt (wewnętrzny).
    • Wpisz identyfikator 56 integer =4 bajty (id kolumna).
    • Wpisz identyfikator 56 integer =4 bajty (c1 kolumna).
    • Wpisz id 175 char(45) =45 bajtów (padding kolumna).
  • Bitmapa zerowa =3 bajty .
  • Nagłówek wiersza narzut =4 bajty .
  • Obliczony rozmiar wiersza =54 + 3 + 4 =61 bajtów .
  • Obliczony rozmiar danych =61 bajtów * 268 wierszy =16 348 bajtów .
  • Obliczone strony danych =16 384 / 8192 =1.99560546875 .

Obliczony rozmiar wiersza (61 bajtów) różni się od rzeczywistego rozmiaru pamięci wiersza (60 bajtów) dodatkowym jednym bajtem wewnętrznych metadanych obecnych w strumieniu wstawiania. Obliczenie nie uwzględnia również 96 bajtów używanych na każdej stronie przez nagłówek strony ani innych rzeczy, takich jak narzut wersjonowania wierszy. Te same obliczenia na SQL Server 2012 dodaje kolejne 4 bajty w wierszu dla ujednolicacza (który nie występuje w unikalnych indeksach, jak wspomniano wcześniej). Dodatkowe bajty oznaczają, że oczekuje się, że na każdej stronie zmieści się mniej wierszy:

  • Obliczony rozmiar wiersza =61 + 4 =65 bajtów .
  • Obliczony rozmiar danych =65 bajtów * 252 wiersze =16 380 bajtów
  • Obliczone strony danych =16 380 / 8192 =1.99951171875 .

Zmiana TOP klauzula od 268 wierszy do 269 (lub od 252 do 253 dla 2012 r.) powoduje, że oczekiwany rozmiar danych jest obliczany tylko przekroczyć minimalny próg 2 stron:

  • Serwer SQL 2014
    • 61 bajtów * 269 wierszy =16 409 bajtów.
    • 16 409 / 8192 =2.0030517578125 stron.
  • SQL Server 2012
    • 65 bajtów * 253 wiersze =16 445 bajtów.
    • 16 445/8192 =2.0074462890625 stron.

Gdy drugi warunek również jest spełniony, DMLRequestSort ma wartość prawda i minimalne rejestrowanie został osiągnięty, jak pokazano na poniższym wyjściu:

Inne ciekawe miejsca:

  • Łącznie generowanych jest 79 rekordów dziennika, w porównaniu z 328 dla wersji z pełnym logowaniem. Mniejsza liczba rekordów logów to oczekiwany wynik minimalnego rejestrowania.
  • LOP_BEGIN_XACT rekordy w minimalnie rejestrowanych rekordy rezerwują stosunkowo dużą ilość miejsca w dzienniku (każdy po 9436 bajtów).
  • Jedną z nazw transakcji wymienionych w zapisach dziennika jest „budowanie indeksu offline” . Chociaż nie prosiliśmy o utworzenie indeksu jako takiego, zbiorcze ładowanie wierszy do pustego indeksu jest zasadniczo tą samą operacją.
  • W pełni zalogowany insert przyjmuje blokadę na poziomie tabeli (Tab-X ), a minimalnie rejestrowane insert przyjmuje modyfikację schematu (Sch-M ) tak jak robi to „prawdziwa” kompilacja indeksu offline.
  • Zbiorcze ładowanie pustej tabeli klastrowej za pomocą INSERT...SELECT z TABLOCK i DMRequestSort ustaw prawdę używa RowsetBulk podobnie jak mechanizm minimalnie rejestrowany stosy w poprzednim artykule.

Szacunki kardynalności

Uważaj na szacunki o niskiej kardynalności na wstawce z indeksem klastrowym operator. Jeśli którykolwiek z progów jest wymagany do ustawienia DMLRequestSort do prawdy nie zostanie osiągnięty z powodu niedokładnego oszacowania liczności, wstawka zostanie w pełni zalogowana , niezależnie od rzeczywistej liczby wierszy i całkowitego rozmiaru danych napotkanych w czasie wykonywania.

Na przykład zmiana TOP klauzula w skrypcie demonstracyjnym, aby użyć zmiennej powoduje stałą kardynalność zgadnij 100 wierszy, czyli poniżej minimum 251 wierszy:

-- Insert rows
DECLARE @NumRows bigint = 269;
 
INSERT dbo.Test WITH (TABLOCK) 
    (c1)
SELECT TOP (@NumRows)
    CHECKSUM(NEWID())
FROM master.dbo.spt_values AS SV;

Buforowanie planu

DMLRequestSort właściwość jest zapisywana jako część buforowanego planu. Gdy plan w pamięci podręcznej jest ponownie używany , wartość DMLRequestSort nie jest ponownie obliczany w czasie wykonywania, chyba że nastąpi ponowna kompilacja. Zauważ, że ponowna kompilacja nie występuje dla TRIVIAL plany oparte na zmianach w statystykach lub kardynalności tabeli.

Jednym ze sposobów uniknięcia nieoczekiwanych zachowań spowodowanych buforowaniem jest użycie OPTION (RECOMPILE) wskazówka. Zapewni to odpowiednie ustawienie dla DMLRequestSort jest obliczana ponownie, kosztem kompilacji przy każdym wykonaniu.

Flaga śledzenia

Możliwe jest wymuszenie DMLRequestSort być ustawionym na prawdę ustawiając nieudokumentowane i nieobsługiwane trace flag 2332, jak pisałem w Optymalizacji zapytań T-SQL, które zmieniają dane. Niestety, to nie wpływa na minimalne logowanie kwalifikowalność do pustych tabel klastrowych — wkładka nadal musi być szacowana na ponad 250 wierszy i 2 strony. Ta flaga śledzenia ma wpływ na inne minimalne rejestrowanie scenariusze, które zostały omówione w ostatniej części tej serii.

Podsumowanie

Zbiorcze ładowanie pustego indeks klastrowy przy użyciu INSERT...SELECT ponownie wykorzystuje RowsetBulk mechanizm używany do zbiorczego ładowania tabel sterty. Wymaga to zablokowania tabeli (zwykle osiągane za pomocą TABLOCK podpowiedź) i ORDER wskazówka. Nie ma możliwości dodania ORDER wskazówka do INSERT...SELECT oświadczenie. W konsekwencji osiągnięcie minimalnego rejestrowania do pustej tabeli klastrowej wymaga, aby DMLRequestSort właściwość wstawki indeksu klastrowego operator jest ustawiony na prawda . To gwarancje do SQL Server, który wiersze są prezentowane w Wstaw operator przybędzie w kolejności klucza indeksu docelowego. Efekt jest taki sam jak przy użyciu ORDER wskazówka dostępna dla innych metod wstawiania zbiorczego, takich jak BULK INSERT i bcp .

Aby wykonać DMLRequestSort być ustawionym na prawdę , musi być:

  • Ponad 250 wierszy szacowany do wstawienia; i
  • Szacunkowa wstaw dane o rozmiarze większym niż dwie strony .

szacowana wstaw obliczenia rozmiaru danych nie dopasuj wynik pomnożenia planu wykonania szacowana liczba wierszy i szacowany rozmiar wiersza właściwości na wejściu do Wstaw operator. Obliczenia wewnętrzne (niepoprawnie) obejmują jedną lub więcej kolumn wewnętrznych w strumieniu wstawiania, które nie są utrwalane w końcowym indeksie. Wewnętrzne obliczenia nie uwzględniają również nagłówków stron ani innych kosztów ogólnych, takich jak wersjonowanie wierszy.

Podczas testowania lub debugowania minimalne logowanie problemów, uważaj na szacunkowe wartości niskiej kardynalności i pamiętaj, że ustawienie DMLRequestSort jest buforowany jako część planu wykonania.

W ostatniej części tej serii szczegółowo opisano warunki wymagane do osiągnięcia minimalnego rejestrowania bez użycia RowsetBulk mechanizm. Odpowiadają one bezpośrednio nowym funkcjom dodanym pod flagą śledzenia 610 do SQL Server 2008, a następnie domyślnie włączonym od SQL Server 2016 i nowszych.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Twój kompletny przewodnik po złączach SQL:OUTER JOIN – część 2

  2. Grupowanie danych za pomocą funkcji OVER i PARTITION BY

  3. DELETE VS DROP w SQL

  4. Jak zainstalować klienta SQL SQuirrel?

  5. Konfigurowanie sieci dedykowanej do komunikacji w grupie dostępności