您应该阅读 Conor Cunningham 撰写的这篇博文:如何编写非 JOIN WHERE 子句。
如果连接类型是INNER
[short] answer usually no
。如果您在 AdventureWorks 数据库 (SQL 2008) 上运行这两个查询:
SET STATISTICS PROFILE ON
GO
SELECT h.SalesOrderID, h.OrderDate, d.LineTotal
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON d.SalesOrderID = h.SalesOrderID
WHERE h.OrderDate = '20010707'
AND d.LineTotal < 100
SELECT h.SalesOrderID, h.OrderDate, d.LineTotal
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON h.OrderDate = '20010707' AND d.SalesOrderID = h.SalesOrderID
WHERE d.LineTotal < 100
GO
SET STATISTICS PROFILE OFF
GO
然后你会得到这些执行计划:
Rows Executes StmtText StmtId NodeId Parent PhysicalOp
-------------------- -------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ----------- ----------- --------------------
5 1 SELECT h.SalesOrderID, h.OrderDate, d.LineTotal
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON d.SalesOrderID = h.SalesOrderID
WHERE h.OrderDate = '20010707'
AND d.LineTotal < 100 1 1 0 NULL NULL NULL
0 0 |--Compute Scalar(DEFINE:([d].[LineTotal]=[AdventureWorks2008].[Sales].[SalesOrderDetail].[LineTotal] as [d].[LineTotal])) 1 2 1 Compute Scalar
5 1 |--Nested Loops(Inner Join, OUTER REFERENCES:([h].[SalesOrderID])) 1 3 2 Nested Loops
4 1 |--Index Seek(OBJECT:([AdventureWorks2008].[Sales].[SalesOrderHeader].[IX_SalesOrderHeader_OrderDate] AS [h]), SEEK:([h].[OrderDate]='2001-07-07 00:00:00.000') ORDERED FORWARD) 1 4 3 Index Seek
0 0 |--Compute Scalar(DEFINE:([d].[LineTotal]=isnull((CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPrice] as [d].[UnitPrice],0)*((1.0)-CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPriceDiscount] as [d].[UnitPriceDiscount],0)))*CONVERT_IMPLICIT(numeric(5,0),[AdventureWorks2008].[Sales].[SalesOrderDetail].[OrderQty] as [d].[OrderQty],0),(0.000000)))) 1 5 3 Compute Scalar
5 4 |--Clustered Index Seek(OBJECT:([AdventureWorks2008].[Sales].[SalesOrderDetail].[PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID] AS [d]), SEEK:([d].[SalesOrderID]=[AdventureWorks2008].[Sales].[SalesOrderHeader].[SalesOrderID] as [h].[SalesOrderID]), WHERE:([AdventureWorks2008].[Sales].[SalesOrderDetail].[SalesOrderID] as [d].[SalesOrderID]>=(1) AND [AdventureWorks2008].[Sales].[SalesOrderDetail].[SalesOrderID] as [d].[SalesOrderID]<=(999999) AND isnull((CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPrice] as [d].[UnitPrice],0)*((1.0)-CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPriceDiscount] as [d].[UnitPriceDiscount],0)))*CONVERT_IMPLICIT(numeric(5,0),[AdventureWorks2008].[Sales].[SalesOrderDetail].[OrderQty] as [d].[OrderQty],0),(0.000000))<(100.000000)) ORDERED FORWARD) 1 6 5 Clustered Index Seek
and
Rows Executes StmtText StmtId NodeId Parent PhysicalOp
-------------------- -------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ----------- ----------- --------------------
5 1 SELECT h.SalesOrderID, h.OrderDate, d.LineTotal
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON h.OrderDate = '20010707' AND d.SalesOrderID = h.SalesOrderID
WHERE d.LineTotal < 100 1 1 0 NULL NULL NULL
0 0 |--Compute Scalar(DEFINE:([d].[LineTotal]=[AdventureWorks2008].[Sales].[SalesOrderDetail].[LineTotal] as [d].[LineTotal])) 1 2 1 Compute Scalar
5 1 |--Nested Loops(Inner Join, OUTER REFERENCES:([h].[SalesOrderID])) 1 3 2 Nested Loops
4 1 |--Index Seek(OBJECT:([AdventureWorks2008].[Sales].[SalesOrderHeader].[IX_SalesOrderHeader_OrderDate] AS [h]), SEEK:([h].[OrderDate]='2001-07-07 00:00:00.000') ORDERED FORWARD) 1 4 3 Index Seek
0 0 |--Compute Scalar(DEFINE:([d].[LineTotal]=isnull((CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPrice] as [d].[UnitPrice],0)*((1.0)-CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPriceDiscount] as [d].[UnitPriceDiscount],0)))*CONVERT_IMPLICIT(numeric(5,0),[AdventureWorks2008].[Sales].[SalesOrderDetail].[OrderQty] as [d].[OrderQty],0),(0.000000)))) 1 5 3 Compute Scalar
5 4 |--Clustered Index Seek(OBJECT:([AdventureWorks2008].[Sales].[SalesOrderDetail].[PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID] AS [d]), SEEK:([d].[SalesOrderID]=[AdventureWorks2008].[Sales].[SalesOrderHeader].[SalesOrderID] as [h].[SalesOrderID]), WHERE:([AdventureWorks2008].[Sales].[SalesOrderDetail].[SalesOrderID] as [d].[SalesOrderID]>=(1) AND [AdventureWorks2008].[Sales].[SalesOrderDetail].[SalesOrderID] as [d].[SalesOrderID]<=(999999) AND isnull((CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPrice] as [d].[UnitPrice],0)*((1.0)-CONVERT_IMPLICIT(numeric(19,4),[AdventureWorks2008].[Sales].[SalesOrderDetail].[UnitPriceDiscount] as [d].[UnitPriceDiscount],0)))*CONVERT_IMPLICIT(numeric(5,0),[AdventureWorks2008].[Sales].[SalesOrderDetail].[OrderQty] as [d].[OrderQty],0),(0.000000))<(100.000000)) ORDERED FORWARD) 1 6 5 Clustered Index Seek
如果您将这些计划与 WinMerge 进行比较,您将看到不同之处:
对于NodeId=1
(代表最终结果集的最后一步SELECT ...
),您会得到差异,因为 SQL 语句不同。但是,对于前面的步骤 ( NodeId=2..6
),有no differences
.
注意 1:在一些奇怪的情况下(ANSI_NULSS ON/OFF
),你可能会得到 diff。结果和差异。执行计划:
SET ANSI_NULLS ON;
SELECT *
FROM (VALUES (1,100),(2,200),(3,NULL)) AS Customer(CustomerID,Limit)
INNER JOIN (VALUES (11,1),(12,1),(13,2),(14,3)) AS [Order](OrderID,CustomerID)
ON Customer.CustomerID=[Order].CustomerID
AND Customer.Limit=NULL
SET ANSI_NULLS OFF;
SELECT *
FROM (VALUES (1,100),(2,200),(3,NULL)) AS Customer(CustomerID,Limit)
INNER JOIN (VALUES (11,1),(12,1),(13,2),(14,3)) AS [Order](OrderID,CustomerID)
ON Customer.CustomerID=[Order].CustomerID
WHERE Customer.Limit=NULL
SET ANSI_NULLS ON;
结果:
CustomerID Limit OrderID CustomerID
----------- ----------- ----------- -----------
(0 row(s) affected)
CustomerID Limit OrderID CustomerID
----------- ----------- ----------- -----------
3 NULL 14 3
(1 row(s) affected)
注2:ANSI_NULLS
设置应始终为ON
。