左连接和内连接之间的性能差异

时间:2013-02-24 09:32:27

标签: sql-server sql-server-2012 left-join inner-join outer-join

左连接和内连接在性能方面有什么区别吗?我使用的是SQL Server 2012。

2 个答案:

答案 0 :(得分:11)

至少有一种情况,LEFT [OUTER] JOIN是比[INNER] JOIN更好的选择。我说的是使用OUTER代替INNER来获得相同的结果。

示例(我正在使用AdventureWorks 2008 database):

-- 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

最后两个查询的执行计划: enter image description here

注1 /查看1:如果我们查看SELECT SalesOrderDetailID FROM View1的执行计划 我们看到FK elimination,因为FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID约束是受信任的,并且它只有一列。但是,服务器被强制(因为INNER JOIN Sales.SpecialOfferProduct)从第三个表(SpecialOfferProduct)读取数据,即使SELECT/WHERE子句不包含此表中的任何列,并且FK约束(FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID)是(也)信任。发生这种情况是因为最后一个FK是多列的。

注意2 /视图2 :如果我们要删除Scan上的阅读(Seek / Sales.SpecialOfferProduct),该怎么办?第二个FK是多列的,在这种情况下,SQL Server无法消除FK(参见之前的Conor Cunnigham博客文章)。在这种情况下,我们需要将INNER JOIN Sales.SpecialOfferProduct替换为LEFT OUTER JOIN Sales.SpecialOfferProduct以便消除FK。 SpecialOfferIDProductID列都是NOT NULL,我们有一个受信任的FK引用SpecialOfferProduct表。

答案 1 :(得分:7)

除了外部联接可能返回更大的结果集的问题,因为保留了额外的行,另一点是优化器在创建执行计划时具有更大的可能性,因为INNER JOIN是可交换的并且缔合

因此,对于以下示例,B已编入索引,但A未编入索引。

CREATE TABLE A(X INT, Filler CHAR(8000))

INSERT INTO A 
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY @@SPID), ''
FROM sys.all_columns

CREATE TABLE B(X INT PRIMARY KEY, Filler CHAR(8000))

INSERT INTO B
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY @@SPID), ''
FROM sys.all_columns

SELECT *
FROM B INNER JOIN A ON A.X = B.X

SELECT *
FROM B LEFT JOIN A ON A.X = B.X

优化器知道B INNER JOIN AA INNER JOIN B是相同的,并生成一个带有嵌套循环的计划,以寻找表B

Plans

此转换对外连接和嵌套循环only supports left outer join not right outer join无效,因此需要使用不同的连接类型。

但是从实际的角度来看,你应该选择你需要的连接类型,它将为你提供正确的语义。