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消除.两者SpecialOfferID和ProductID列都是NOT NULL,我们有一个可信的FK引用SpecialOfferProduct表.
除了外部联接可能返回更大的结果集的问题,因为保留了额外的行,另一点是优化器在创建执行计划时具有更大的可能性,因为它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.

此转换对外连接无效,嵌套循环仅支持左外连接而不是右外连接,因此需要使用不同的连接类型.
但从实际角度来看,您应该选择所需的连接类型,以便为您提供正确的语义.
| 归档时间: |
|
| 查看次数: |
6174 次 |
| 最近记录: |