Istnieje co najmniej jeden przypadek, w którym LEFT [OUTER] JOIN
jest lepszą opcją niż [INNER] JOIN
. Mówię o uzyskaniu tych samych wyników przy użyciu OUTER
zamiast INNER
.
Przykład (używam bazy danych AdventureWorks 2008 ):
-- Some metadata infos
SELECT fk.is_not_trusted, fk.name
FROM sys.foreign_keys fk
WHERE fk.parent_object_id=object_id('Sales.SalesOrderDetail');
GO
CREATE VIEW View1
AS
SELECT h.OrderDate, d.SalesOrderDetailID, o.ModifiedDate
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON d.SalesOrderID = h.SalesOrderID
INNER JOIN Sales.SpecialOfferProduct o ON d.SpecialOfferID=o.SpecialOfferID AND d.ProductID=o.ProductID;
GO
CREATE VIEW View2
AS
SELECT h.OrderDate, d.SalesOrderDetailID, o.ModifiedDate
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON d.SalesOrderID = h.SalesOrderID
LEFT JOIN Sales.SpecialOfferProduct o ON d.SpecialOfferID=o.SpecialOfferID AND d.ProductID=o.ProductID;
GO
SELECT SalesOrderDetailID
FROM View1;
SELECT SalesOrderDetailID
FROM View2;
Wyniki dla pierwszego zapytania:
is_not_trusted name
-------------- ---------------------------------------------------------------
0 FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
0 FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID
Plany wykonania dla dwóch ostatnich zapytań:
Uwaga 1 / Widok 1: Jeśli spojrzymy na plan wykonania dla SELECT SalesOrderDetailID FROM View1
widzimy eliminacja FK
ponieważ FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
ograniczenie jest zaufane i ma jedną kolumnę. Ale serwer jest wymuszony (z powodu INNER JOIN Sales.SpecialOfferProduct
) aby odczytać dane z trzeciej tabeli (SpecialOfferProduct) nawet SELECT/WHERE
klauzule nie zawierają żadnych kolumn z tej tabeli, a ograniczenie FK (FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID) jest (również) zaufane. Dzieje się tak, ponieważ ten ostatni FK jest wielokolumnowy.
Uwaga 2 / Widok 2: Co jeśli chcemy usunąć odczytane (Scan
/Seek
) na Sales.SpecialOfferProduct
? Ten drugi plik FK jest wielokolumnowy iw takich przypadkach SQL Server nie może go wyeliminować (patrz poprzedni wpis na blogu Conora Cunnighama). W takim przypadku musimy zastąpić INNER JOIN Sales.SpecialOfferProduct
z LEFT OUTER JOIN Sales.SpecialOfferProduct
aby uzyskać eliminację FK. Oba SpecialOfferID
i ProductID
kolumny są NOT NULL
i mamy zaufany FK odwołujący się do SpecialOfferProduct
tabela.