至少有一种情况LEFT [OUTER] JOIN
是一个更好的选择[INNER] JOIN
。我谈到使用获得相同的结果OUTER
代替INNER
.
示例(我正在使用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;
第一个查询的结果:
is_not_trusted name
-------------- ---------------------------------------------------------------
0 FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
0 FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID
Execution plans for the last two queries:
注 1/视图 1:如果我们看一下执行计划SELECT SalesOrderDetailID FROM View1
我们看到一个FK消除因为FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
约束是可信的并且它只有一个列。但是,服务器是被迫的(因为INNER JOIN Sales.SpecialOfferProduct
)从第三个表(SpecialOfferProduct)读取数据,甚至SELECT/WHERE
子句不包含此表中的任何列,并且 FK 约束 (FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID) 也是受信任的。发生这种情况是因为最后一个 FK 是多列的。
注 2/视图 2:如果我们想删除 read (Scan
/Seek
)在Sales.SpecialOfferProduct
?第二个 FK 是多列的,对于这种情况,SQL Server 无法消除 FK(请参阅之前的 Conor Cunnigham 博客文章)。在这种情况下我们需要更换INNER JOIN Sales.SpecialOfferProduct
with LEFT OUTER JOIN Sales.SpecialOfferProduct
以达到FK淘汰的目的。两个都SpecialOfferID
and ProductID
列是NOT NULL
我们有一个值得信赖的 FK 参考SpecialOfferProduct
table.