在JOIN中添加WHERE条件

时间:2013-02-24 06:17:49

标签: sql sql-server performance sql-server-2008 database-performance

我有以下查询来过滤给定城市和横幅中的活动商店

SELECT ShopName,CityName 
FROM Shop S INNER JOIN City C ON C.CityId=S.CityId
WHERE S.Active=1 AND S.Banner like '%res%'

SELECT ShopName,CityName 
FROM Shop S INNER JOIN City C ON C.CityId=S.CityId AND S.Active=1
WHERE S.Banner like '%res%'

如果您查看两个查询,它们会给出相同的结果,但在不同的地方使用S.Active。一个是IN JOIN,另一个是WHERE Clause。

哪个查询效果会更好?

  

我在City表中有300万个城市,在Shops表中有40000,000个商店。   我为(City,Active)创建了NON Clustered index

3 个答案:

答案 0 :(得分:2)

您应该阅读Conor Cunningham撰写的这篇博文: How to write non-JOIN WHERE clauses

如果联接类型为INNER,则[短]回答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进行比较,那么您将看到差异: enter image description here

对于NodeId=1(表示最终结果集SELECT ...的最后一步),您将获得差异,因为SQL语句不同。但是,对于之前的步骤(NodeId=2..6),有no differences

注1 :在某些奇怪的情况下(ANSI_NULSS ON/OFF),您可能会遇到差异。结果和差异。执行计划:

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)

enter image description here

注意2 ANSI_NULLS设置应始终为ON

答案 1 :(得分:0)

它们是相同的,但它应该在JOIN中。

在过去,JOIN没有ON,因此连接在WHERE中。但是ANSI在JOIN中引入了ON,现代SQL引擎会自动将WHERE转换为ON。

在您的方案中,重要的是您在C.CityId上有一个索引

答案 2 :(得分:0)

不要强调哪个会表现得更好。您必须了解SQL是DECLARATIVE而不是PROCEDURAL语言。用简单的英语,查询优化器会将您的查询转换为将运行的实际代码。在所有可能性中,它将完全相同。

您可以查看查询计划以确定,但即使它们不同,这种过早优化也是浪费时间。在您知道自己遇到问题时进行优化,而不是在编写查询之前进行优化。