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

meh*_*tfi 3 sql-server inner-join left-join outer-join sql-server-2012

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

Bog*_*ean 11

至少有一种情况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;
Run Code Online (Sandbox Code Playgroud)

第一个查询的结果:

is_not_trusted name
-------------- ---------------------------------------------------------------
0              FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
0              FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID
Run Code Online (Sandbox Code Playgroud)

最后两个查询的执行计划: 在此输入图像描述

注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:如果我们要删除读(Scan/ Seek)Sales.SpecialOfferProduct怎么办?第二个FK是多列的,在这种情况下,SQL Server无法消除FK(参见之前的Conor Cunnigham博客文章).在这种情况下,我们需要替换INNER JOIN Sales.SpecialOfferProductwith LEFT OUTER JOIN Sales.SpecialOfferProduct以获得FK消除.两者SpecialOfferIDProductID列都是NOT NULL,我们有一个可信的FK引用SpecialOfferProduct表.


Mar*_*ith 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
Run Code Online (Sandbox Code Playgroud)

优化器知道B INNER JOIN A并且 A INNER JOIN B是相同的,并生成一个带有嵌套循环的计划B.

计划

此转换对外连接无效,嵌套循环仅支持左外连接而不是右外连接,因此需要使用不同的连接类型.

但从实际角度来看,您应该选择所需的连接类型,以便为您提供正确的语义.