3

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

4

2 回答 2

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;

第一个查询的结果:

is_not_trusted name
-------------- ---------------------------------------------------------------
0              FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
0              FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID

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

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

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

于 2013-02-24T10:06:57.813 回答
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是相同的,并生成一个带有嵌套循环的计划,用于查找 table B

计划

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

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

于 2013-02-24T10:01:04.823 回答