Conor Cunningham によって書かれたこのブログ投稿を読む必要があります: How to write non-JOIN WHERE clauses .
結合タイプがINNER
[短い] answer の場合usually no
。AdventureWorks データベース (SQL 2008) で次の 2 つのクエリを実行すると、次のようになります。
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
。