sql >> Databáze >  >> RDS >> Sqlserver

Vyloučení spojení:Když SQL Server odstraní nepotřebné tabulky

Hostující autor:Bert Wagner (@bertwagner)

Eliminace spojení je jednou z mnoha technik, které optimalizátor dotazů SQL Server používá k vytváření efektivních plánů dotazů. Konkrétně k eliminaci spojení dochází, když SQL Server dokáže nastolit rovnost pomocí logiky dotazu nebo omezení důvěryhodné databáze k odstranění zbytečných spojení. Podívejte se na plnou verzi videa tohoto příspěvku na mém kanálu YouTube.

Připojte se k eliminaci v akci

Nejjednodušší způsob, jak vysvětlit eliminaci připojení, je prostřednictvím série ukázek. Pro tyto příklady budu používat demo databázi WideWorldImporters.

Pro začátek se podíváme, jak funguje eliminace spojení, když je přítomen cizí klíč:

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

V tomto příkladu vracíme data pouze z Sales.InvoiceLines, kde je v Sales.Invoices nalezeno odpovídající InvoiceID. I když můžete očekávat, že plán realizace zobrazí operátora spojení v tabulkách Sales.InvoiceLines a Sales.Invoices, SQL Server se nikdy neobtěžuje dívat se na Sales.Invoices:

SQL Server se vyhýbá připojení k tabulce Sales.Invoices, protože důvěřuje referenční integritě udržované omezením cizího klíče definovaného na InvoiceID mezi Sales.InvoiceLines a Sales.Invoices; pokud v Sales.InvoiceLines existuje řádek, řádek s odpovídající hodnotou pro InvoiceID musí existují v Sales.Invoices. A protože vracíme pouze data z tabulky Sales.InvoiceLines, SQL Server vůbec nemusí číst žádné stránky z Sales.Invoices.

Můžeme ověřit, že SQL Server používá omezení cizího klíče k odstranění spojení zrušením omezení a spuštěním našeho dotazu znovu:

ALTER TABLE [Sales].[InvoiceLines] DROP CONSTRAINT [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];

Bez informací o vztahu mezi našimi dvěma tabulkami je SQL Server nucen provést spojení, skenovat index v naší tabulce Sales.Invoices, aby našel odpovídající InvoiceID.

Z hlediska I/O musí SQL Server přečíst dalších 124 stránek z indexu v tabulce Sales.Invoices, a to pouze proto, že je schopen použít úzký (jednosloupcový) index vytvořený jiným omezením cizího klíče. Tento scénář by mohl dopadnout mnohem hůře na větších stolech nebo tabulkách, které nejsou správně indexovány.

Omezení

Zatímco předchozí příklad ukazuje základy toho, jak eliminace spojení funguje, musíme si být vědomi několika upozornění.

Nejprve přidejte zpět naše omezení cizího klíče:

ALTER TABLE [Sales].[InvoiceLines] S NOCHECK ADD OMEZENÍ [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices] CIZÍ KLÍČ([ID faktury])REFERENCE [Prodej].[Faktury] ([pre>ID faktury]); 

Pokud znovu spustíme náš ukázkový dotaz, všimneme si, že nezískáme plán, který by vykazoval eliminaci spojení; místo toho dostaneme plán, který prohledá oba naše spojené stoly.

Důvodem je to, že když jsme znovu přidali naše omezení cizího klíče, SQL Server neví, zda byla mezitím nějaká data změněna. Jakákoli nová nebo změněná data nemusí splňovat toto omezení, takže SQL Server nemůže důvěřovat platnosti našich dat:

SELECT f.name AS cizí_klíč_název ,OBJECT_NAME(f.parent_object_id) AS název_tabulky ,COL_NAME(fc.parent_object_id, fc.parent_column_id) AS constraint_column_name ,OBJECT_NAME (f.referenced_object_ID) AScd. ) 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('voiceLinesa>les' 

Abychom znovu nastolili důvěru serveru SQL k tomuto omezení, musíme zkontrolovat jeho platnost:

ZMĚŇTE TABULKU [Sales].[InvoiceLines] S OMEZENÍM KONTROLY [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];

U velkých tabulek může tato operace nějakou dobu trvat, nemluvě o režii SQL Serveru, která tato data ověřuje během každé modifikace vložení/aktualizace/odstranění.

Dalším omezením je, že SQL Server nemůže odstranit spojené tabulky, když dotaz potřebuje vrátit jakákoli data z těchto potenciálních kandidátů na odstranění:

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

Ve výše uvedeném dotazu nedochází k eliminaci spojení, protože požadujeme, aby byla vrácena data z Sales.Invoices, což SQL Server přinutí číst data z této tabulky.

Nakonec je důležité poznamenat, že k odstranění spojení nedojde, pokud má cizí klíč více sloupců nebo pokud jsou tabulky v databázi tempdb. To je jeden z několika důvodů, proč byste se neměli pokoušet řešit problémy s optimalizací zkopírováním tabulek do databáze tempdb.

Další scénáře

Více tabulek

Eliminace spojení se neomezuje pouze na vnitřní spojení dvou tabulek a tabulky s omezením cizího klíče.

Můžeme například vytvořit další tabulku, která odkazuje na náš sloupec Sales.Invoices.InvoiceID:

CREATE TABLE Sales.InvoiceClickTracking ( InvoiceClickTrackingID bigint PRIMÁRNÍ KLÍČ IDENTITY, InvoiceID int -- ostatní pole by patřila sem ); PŘEJDĚTE ZMĚNIT TABULKU [Prodej].[InvoiceClickTracking] SE ZKONTROLUJTE PŘIDAT OMEZENÍ [FK_Sales_InvoiceClickTracking_InvoiceID_Sales_Invoices] CIZÍ KLÍČ([ID faktury]) REFERENCE [Prodej].[Faktury] ([InvoiceID]); 

Připojení této tabulky k našemu původnímu vzorovému dotazu také umožní serveru SQL Server odstranit naši tabulku 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 může eliminovat tabulku Sales.Invoices kvůli přechodné asociaci mezi vztahy těchto tabulek.

Jedinečná omezení

Namísto omezení cizího klíče SQL Server také provede eliminaci spojení, pokud může důvěřovat datovému vztahu s jedinečným omezením:

ALTER TABLE [Prodej].[InvoiceClickTracking] DROP CONSTRAINT [FK_Sales_InvoiceClickTracking_InvoiceID_Sales_Invoices]; GO ALTER TABLE Sales.InvoiceClickTracking ADD CONSTRAINT UQ_InvoiceID UNIQUE (InvoiceID); GO SELECT i.InvoiceID FROM Sales.InvoiceClickTracking ict RIGHT PŘIPOJTE SE k Sales.Invoices i ON ict.InvoiceID =i.InvoiceID;

Vnější spojení

Dokud SQL Server dokáže odvodit omezení vztahu, může dojít k odstranění tabulky i u jiných typů spojení. Například:

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

Vzhledem k tomu, že stále máme omezení cizího klíče, které vynucuje, že každé InvoiceID v Sales.InvoiceLines musí mít odpovídající InvoiceID v Sales.Invoices, SQL Server nemá problém vrátit vše z Sales.InvoiceLInes, aniž by bylo nutné se připojit k Sales.Invoices:

Není vyžadováno žádné omezení

Pokud SQL Server může zaručit, že nebude potřebovat data z určité tabulky, může potenciálně eliminovat spojení.

V tomto dotazu nedochází k žádné eliminaci spojení, protože SQL Server nedokáže identifikovat, zda je vztah mezi Sales.Invoices a Sales.InvoiceLines 1-to-1, 1-to-0 nebo 1-to-many. Je nucen číst Sales.InvoiceLines, aby zjistil, zda byly nalezeny nějaké odpovídající řádky:

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

Pokud však určíme, že chceme DISTINCT sadu i.InvoiceIDs, každá jedinečná hodnota z Sales.Invoices se vrátí ze serveru SQL bez ohledu na to, jaký vztah mají tyto řádky k Sales.InvoiceLines.

-- Abychom dokázali, že se zde nehraje o žádný cizí klíč, ZMĚŇTE TABULU [Sales].[InvoiceLines] DROP CONSTRAINT [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];GO -- Naše odlišná sada výsledkůSELECT DISTINCT i.InvoiceIDFROM Sales.RIGHT JOINvoiceLines. i ON il.InvoiceID =i.InvoiceID;

Zobrazení

Jednou z výhod eliminace spojení je, že může pracovat s pohledy, i když podkladový dotaz pohledu nemůže použít eliminaci spojení:

-- Přidejte zpět naši FK ALTER TABLE [Sales].[InvoiceLines] SE KONTROLOU PŘIDAT OMEZENÍ [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices] CIZÍ KLÍČ([ID faktury])REFERENCE -- [Prodej][Faktury] (GO); náš pohled pomocí dotazu, který nelze použít join eliminationCREATE 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.InvoiceID GO -- Vyloučení spojení funguje, protože nevybíráme žádné -- sloupce ze základní tabulky Sales.Invoices SELECT Quantity, TaxRate FROM Sales.vInvoicesAndInvoiceLines;

Závěr

Eliminace spojení je optimalizace, kterou SQL Server provede, když zjistí, že může poskytnout přesnou sadu výsledků, aniž by bylo nutné číst data ze všech tabulek zadaných v odeslaném dotazu. Tato optimalizace může poskytnout významné zlepšení výkonu snížením počtu stránek, které musí SQL Server přečíst, avšak často je to na úkor nutnosti udržovat určitá databázová omezení. Dotazy můžeme refaktorovat tak, abychom dosáhli jednodušších plánů provádění, které eliminace spojení poskytuje, ale to, že optimalizátor dotazů automaticky zjednoduší naše plány odstraněním nepotřebných spojení, je příjemnou výhodou.

Znovu vás zvu ke shlédnutí celé video verze tohoto příspěvku.

O autorovi

Bert je vývojář business intelligence z Clevelandu ve státě Ohio. Miluje psaní rychle běžících dotazů a rád pomáhá ostatním naučit se být soběstačnými řešiteli problémů SQL. Bert bloguje o SQL Serveru na bertwagner.com a vytváří SQL Server YouTube videa na youtube.com/c/bertwagner.
  1. Oracle Concurrent Manager – CP Analyzer pro E-Business Suite

  2. Jak získat včerejší datum v MySQL

  3. SQL Server:DELETE vs TRUNCATE

  4. Zahoďte milisekundovou část z časového razítka