Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Eliminacja przyłączeń:gdy SQL Server usuwa niepotrzebne tabele

Gość autor:Bert Wagner (@bertwagner)

Eliminacja sprzężeń jest jedną z wielu technik używanych przez optymalizator zapytań SQL Server do tworzenia wydajnych planów zapytań. W szczególności eliminacja sprzężeń ma miejsce, gdy program SQL Server może ustanowić równość przy użyciu logiki zapytań lub ograniczeń zaufanej bazy danych w celu wyeliminowania niepotrzebnych sprzężeń. Zobacz pełną wersję wideo tego posta na moim kanale YouTube.

Dołącz do eliminacji w akcji

Najprostszym sposobem wyjaśnienia eliminacji łączenia jest seria demonstracji. W tych przykładach użyję demonstracyjnej bazy danych WideWorldImporters.

Na początek przyjrzymy się, jak działa eliminacja dołączenia, gdy obecny jest klucz obcy:

SELECT il.* FROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID;

W tym przykładzie zwracamy dane tylko z Sales.InvoiceLines, gdzie w Sales.Invoices znajduje się pasujący identyfikator faktury. Chociaż można by oczekiwać, że plan wykonania pokaże operator łączenia w tabelach Sales.InvoiceLines i Sales.Invoices, SQL Server nigdy nie zawraca sobie głowy przeglądaniem Sales.Faktury:

SQL Server unika dołączania do tabeli Sales.Invoices, ponieważ ufa integralności referencyjnej utrzymywanej przez ograniczenie klucza obcego zdefiniowane w InvoiceID między Sales.InvoiceLines i Sales.Invoices; jeśli wiersz istnieje w Sales.InvoiceLines, wiersz z pasującą wartością dla InvoiceID musi istnieją w Sales.Invoices. A ponieważ zwracamy tylko dane z tabeli Sales.InvoiceLines, SQL Server nie musi w ogóle odczytywać żadnych stron z Sales.Invoices.

Możemy sprawdzić, czy SQL Server używa ograniczenia klucza obcego do wyeliminowania sprzężenia, usuwając ograniczenie i ponownie uruchamiając nasze zapytanie:

ZMIEŃ TABELĘ [Sprzedaż].[InvoiceLines] OGRANICZENIE UPUSZCZANIA [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];

Brak informacji o relacji między naszymi dwiema tabelami powoduje, że SQL Server jest zmuszony wykonać łączenie, skanując indeks w naszej tabeli Sales.Invoices w celu znalezienia pasujących identyfikatorów InvoiceID.

Z punktu widzenia we/wy, SQL Server musi odczytać dodatkowe 124 strony z indeksu w tabeli Sales.Invoices, a to tylko dlatego, że jest w stanie użyć wąskiego (jednokolumnowego) indeksu utworzonego przez inne ograniczenie klucza obcego. Ten scenariusz może być znacznie gorszy na większych stołach lub stołach, które nie są odpowiednio indeksowane.

Ograniczenia

Podczas gdy poprzedni przykład pokazuje podstawy tego, jak działa eliminacja łączenia, musimy być świadomi kilku zastrzeżeń.

Najpierw dodajmy ponownie nasze ograniczenie klucza obcego:

ZMIEŃ TABELĘ [Sprzedaż].[InvoiceLines] Z OGRANICZENIEM DODANIA NOCHECK [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices] KLUCZ OBCY([InvoiceID])REFERENCJE [Sprzedaż].[Faktury] ([InvoiceID]);

Jeśli ponownie uruchomimy nasze przykładowe zapytanie, zauważymy, że nie otrzymamy planu, który uwzględniałby eliminację eksponatów; zamiast tego otrzymujemy plan, który skanuje obie nasze połączone tabele.

Powodem tego jest to, że kiedy ponownie dodaliśmy nasze ograniczenie klucza obcego, SQL Server nie wie, czy jakiekolwiek dane zostały w międzyczasie zmodyfikowane. Wszelkie nowe lub zmienione dane mogą nie być zgodne z tym ograniczeniem, więc SQL Server nie może ufać ważności naszych danych:

SELECT f.name AS nazwa_klucza_obcego ,NAZWA_OBIEKTU(f.id_obiektu_nadrzędnego) AS nazwa_tabeli ,COL_NAME(fc.id_obiektu_nadrzędnego, fc.identyfikator_kolumny_nadrzędnej) AS nazwa_kolumny_ograniczenia ,NAZWA_OBIEKTU (f.id_obiektu_odniesienia. ) AS referenced_column_name ,f.is_not_trustedFROM sys.foreign_keys AS f INNER JOIN sys.foreign_key_columns AS fc ON f.object_id =fc.constraint_object_idWHERE f.parent_object_id =OBJECT_ID (>preLines.);
 

Aby przywrócić zaufanie SQL Server do tego ograniczenia, musimy sprawdzić jego poprawność:

ZMIEŃ TABELĘ [Sprzedaż].[InvoiceLines] Z OGRANICZENIEM SPRAWDŹ SPRAWDŹ [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];

W przypadku dużych tabel operacja ta może zająć trochę czasu, nie wspominając o obciążeniu SQL Server weryfikującym te dane podczas każdej kolejnej modyfikacji wstawiania/aktualizacji/usuwania.

Innym ograniczeniem jest to, że SQL Server nie może wyeliminować połączonych tabel, gdy zapytanie musi zwrócić jakiekolwiek dane z tych potencjalnych kandydatów do eliminacji:

SELECT il.*, i.InvoiceDateFROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID;

Eliminacja sprzężenia nie występuje w powyższym zapytaniu, ponieważ żądamy danych z działu Sales.Faktury są zwracane, co zmusza SQL Server do odczytania danych z tej tabeli.

Na koniec należy zauważyć, że eliminacja sprzężenia nie nastąpi, gdy klucz obcy ma wiele kolumn lub jeśli tabele znajdują się w tempdb. To ostatnie jest jednym z kilku powodów, dla których nie powinieneś próbować rozwiązywać problemów z optymalizacją poprzez kopiowanie tabel do tempdb.

Dodatkowe scenariusze

Wiele stołów

Eliminacja złączeń nie ogranicza się tylko do dwutabelowych złączeń wewnętrznych i tabel z ograniczeniami klucza obcego.

Na przykład możemy utworzyć dodatkową tabelę, która odwołuje się do naszej kolumny Sales.Invoices.InvoiceID:

CREATE TABLE Sales.InvoiceClickTracking ( InvoiceClickTrackingID bigint IDENTITY KLUCZ PODSTAWOWY, InvoiceID int — inne pola zostaną umieszczone w tym miejscu ); PRZEJDŹ ALTER TABELA [Sprzedaż].[InvoiceClickTracking] Z SPRAWDŹ DODAJ OGRANICZENIE [FK_Sales_InvoiceClickTracking_InvoiceID_Sales_Invoices] KLUCZ OBCY([InvoiceID]) ODNIESIENIA [Sprzedaż].[Faktury] ([InvoiceID]);

Dołączenie tej tabeli do naszego oryginalnego przykładowego zapytania pozwoli również SQL Serverowi wyeliminować naszą tabelę Sales.Invoices:

SELECT il.InvoiceID, ict.InvoiceID FROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID INNER JOIN Sales.InvoiceClickTracking ict ON i.InvoiceID =ict.InvoiceID;

SQL Server może wyeliminować tabelę Sales.Invoices ze względu na przechodnie powiązania między relacjami tych tabel.

Unikalne ograniczenia

Zamiast ograniczenia klucza obcego, SQL Server wykona również eliminację sprzężenia, jeśli może zaufać relacji danych z unikalnym ograniczeniem:

 ALTER TABELA [Sprzedaż]. [InvoiceClickTracking] OGRANICZENIE UPUSZCZANIA [FK_Sales_InvoiceClickTracking_InvoiceID_Sales_Invoices]; GO ALTER TABLE Sales.InvoiceClickTracking DODAJ OGRANICZENIE UQ_InvoiceID UNIQUE (InvoiceID); GO SELECT i.InvoiceID FROM Sales.InvoiceClickTracking ict RIGHT JOIN Sales.Invoices i ON ict.InvoiceID =i.InvoiceID;

Połączenia zewnętrzne

Dopóki SQL Server może wywnioskować ograniczenia relacji, inne typy sprzężeń również mogą doświadczyć eliminacji tabeli. Na przykład:

SELECT il.InvoiceIDFROM Sales.InvoiceLines LEFT JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID

Ponieważ nadal mamy ograniczenie klucza obcego wymuszające, że każdy InvoiceID w Sales.InvoiceLines musi mieć odpowiedni InvoiceID w Sales.Invoices, SQL Server nie ma problemu ze zwróceniem wszystkiego z Sales.InvoiceLINEs bez konieczności dołączania do Sales.Invoices:

Żadne ograniczenia nie są wymagane

Jeśli SQL Server może zagwarantować, że nie będzie potrzebować danych z określonej tabeli, może potencjalnie wyeliminować łączenie.

W tej kwerendzie nie występuje eliminacja sprzężenia, ponieważ SQL Server nie może określić, czy relacja między Sales.Invoices i Sales.InvoiceLines wynosi 1 do 1, 1 do 0 czy 1 do wielu. Jest zmuszony do przeczytania Sales.InvoiceLines, aby określić, czy znaleziono pasujące wiersze:

SELECT i.InvoiceIDFROM Sales.InvoiceLines il RIGHT JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID;

Jeśli jednak określimy, że chcemy mieć DISTINCT zestaw i.InvoiceIDs, każda unikalna wartość z Sales.Invoices zostanie zwrócona z SQL Server, niezależnie od relacji między tymi wierszami a Sales.InvoiceLines.

-- Aby udowodnić, że nie ma tu żadnego klucza obcego ALTER TABELA [Sprzedaż]. [InvoiceLines] OGRANICZENIE UPUSZCZENIA [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];GO - Nasz odrębny zestaw wynikówSELECT DISTINCT i.InvoiceIDFROM Sales.InvoiceLines il RIGHT JOIN Sales. i ON il.InvoiceID =i.InvoiceID;

Wyświetlenia

Jedną z zalet eliminacji sprzężenia jest to, że może działać z widokami, nawet jeśli bazowe zapytanie widoku nie może używać eliminacji sprzężenia:

-- Dodaj z powrotem naszą FK ALTER TABLE [Sprzedaż].[InvoiceLines] Z SPRAWDŹ OGRANICZENIE DODAJ [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices] KLUCZ OBCY([InvoiceID])REFERENCES [Sales].[Faktury] ([InvoiceID]);GO -- Utwórz nasz widok za pomocą zapytania, które nie może korzystać z połączenia eliminacjiCREATE VIEW Sales.vInvoicesAndInvoiceLinesAS SELECT i.InvoiceID, i.InvoiceDate, il.Quantity, il.TaxRate FROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.Invoice; GO -- Eliminacja łączenia działa, ponieważ nie wybieramy żadnych -- kolumn z podstawowej tabeli Sales.Invoices SELECT Quantity, TaxRate FROM Sales.vInvoicesAndInvoiceLines;

Wniosek

Eliminacja sprzężeń to optymalizacja wykonywana przez program SQL Server, gdy stwierdzi, że może dostarczyć dokładny zestaw wyników bez konieczności odczytywania danych ze wszystkich tabel określonych w przesłanym zapytaniu. Ta optymalizacja może zapewnić znaczną poprawę wydajności poprzez zmniejszenie liczby stron, które SQL Server musi odczytać, jednak często odbywa się to kosztem konieczności utrzymania pewnych ograniczeń bazy danych. Możemy refaktoryzować zapytania, aby osiągnąć prostsze plany wykonania, które zapewnia eliminacja złączeń, jednak posiadanie optymalizatora zapytań automatycznie upraszcza nasze plany, usuwając niepotrzebne złączenia, jest miłą korzyścią.

Ponownie zapraszam do obejrzenia pełnej wersji wideo tego posta.

O autorze

Bert jest programistą analizy biznesowej z Cleveland w stanie Ohio. Uwielbia pisać szybko działające zapytania i lubi pomagać innym w nauce samodzielnego rozwiązywania problemów SQL. Bert pisze bloga o SQL Server na bertwagner.com i tworzy filmy na YouTube dotyczące SQL Server na youtube.com/c/bertwagner.
  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Przykłady SQRT() w SQL Server

  2. Zmień separator na przecinek podczas wysyłania wyników zapytania pocztą e-mail w programie SQL Server (T-SQL)

  3. Jak zmienić numer sekwencyjny konta pocztowego bazy danych w profilu w programie SQL Server (T-SQL)

  4. SQL Server Najnowsze wersje, edycje i historia SQL Server

  5. 2 sposoby sprawdzenia, czy przestarzałe funkcje są nadal używane w wystąpieniu programu SQL Server