我有以下查询来过滤给定城市和横幅中的活动商店
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
答案 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进行比较,那么您将看到差异:
对于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)
注意2 :ANSI_NULLS
设置应始终为ON
。
答案 1 :(得分:0)
它们是相同的,但它应该在JOIN中。
在过去,JOIN没有ON,因此连接在WHERE中。但是ANSI在JOIN中引入了ON,现代SQL引擎会自动将WHERE转换为ON。
在您的方案中,重要的是您在C.CityId上有一个索引
答案 2 :(得分:0)
不要强调哪个会表现得更好。您必须了解SQL是DECLARATIVE而不是PROCEDURAL语言。用简单的英语,查询优化器会将您的查询转换为将运行的实际代码。在所有可能性中,它将完全相同。
您可以查看查询计划以确定,但即使它们不同,这种过早优化也是浪费时间。在您知道自己遇到问题时进行优化,而不是在编写查询之前进行优化。