2013-02-24 219 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所以它需要使用不同的聯接類型。

但是從實際的角度來看,你應該選擇你需要的連接類型,它會給你正確的語義。