2013-02-24 181 views
3

左连接和内连接之间在性能方面是否有区别?我使用的是SQL Server 2012.左连接和内连接之间的性能差异

+4

是的,可能有区别。但你为什么在意?这2个不等同,并且(通常)会产生不同的结果。因此,请使用对您的查询有用的信息,并为您提供所需的结果。 – 2013-02-24 09:36:28

+0

[INNER JOIN vs LEFT JOIN性能在SQL Server中]的可能的重复(http://stackoverflow.com/questions/2726657/inner-join-vs-left-join-performance-in-sql-server) – 2013-02-24 09:45:58

回答

11

至少有一种情况,其中LEFT [OUTER] JOIN[INNER] JOIN更好。我谈到使用OUTER而不是INNER获得相同的结果。

示例(我使用​​):

-- 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:如果我们看一下的执行计划 我们看到一个FK elimination,因为FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID约束是可信的并且它只有一个列。但是,服务器被迫(因为INNER JOIN Sales.SpecialOfferProduct)从第三个表(SpecialOfferProduct)读取数据,即使SELECT/WHERE子句不包含此表中的任何列,并且(也)信任FK约束(FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID)。发生这种情况是因为这最后一个FK是多列。

注2 /浏览2:如果我们想在​​删除读(Scan/Seek)?这第二个FK是多列,对于这种情况,SQL Server无法消除FK(请参阅前面的Conor Cunnigham博客文章)。在这种情况下,我们需要将INNER JOIN Sales.SpecialOfferProduct替换为LEFT OUTER JOIN Sales.SpecialOfferProduct以获得FK消除。 SpecialOfferIDProductID列都是NOT NULL,我们有一个可信的FK参考SpecialOfferProduct表。

+0

@MartinSmith:我现在添加一些注释,但在这种情况下**它们具有相同的语义。 – 2013-02-24 10:17:44

+0

只有在引用'SpecialOfferProduct'的'SalesOrderDetail'中有'FOREIGN KEY'时,它们才具有相同的语义。 – 2013-02-24 10:24:07

+0

@ypercube:'FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID' – 2013-02-24 10:25:25

6

除了外连接可能由于保留附加行而返回更大结果集的问题之外,还有一点是优化程序在创建执行计划时具有更大范围的可能性,因为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所以它需要使用不同的联接类型。

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