0

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

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 子句。

哪个查询会执行得更好?

我在 City 表中有 3000000 个城市,在 Shops 表中有 40000000 个商店。我为 (City,Active) 创建了非聚集索引

4

3 回答 3

2

您应该阅读 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)

在此处输入图像描述

注2ANSI_NULLS设置应始终为ON

于 2013-02-24T07:14:14.967 回答
0

不要强调哪个会表现更好。您必须了解 SQL 是一种声明性语言而不是一种过程性语言。简单来说,您的查询将由查询优化器转换为将要运行的实际代码。在所有可能的情况下,这将是完全相同的。

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

于 2013-02-24T07:06:22.830 回答
0

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

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

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

于 2013-02-24T06:48:54.000 回答