我在SQL Server 2008中有两个表 -
Sales.SalesOrderHeader --> CustomerID(FK, int, not null), OrderDate
(datetime, not null), etc...
Sales.Individual --> CustomerID(PK, FK, int, not null), ContactID
(FK, int, not null), etc...
我必须找到订单最后一天订购的客户(即CustomerID和对应的ContactID)。
此查询用于查找最后一个OrderDate
select MAX(Soh.OrderDate)
from Sales.SalesOrderHeader as Soh
现在,接下来要做的是获取CustomerID和Contact ID。我想到了 两种方法 - 仅使用子查询和where子句或Join和一个子查询。 这两种方法如下所示:
- Style1:仅使用子查询
select Si.CustomerID, Si.ContactID
from Sales.Individual as Si
where Si.CustomerID in
(
select Soh.CustomerID
from Sales.SalesOrderHeader as Soh
where Soh.OrderDate =
(
select MAX(Soh.OrderDate)
from Sales.SalesOrderHeader as Soh
)
)
order by Si.CustomerID, Si.ContactID
- 样式2:使用内连接
select CustOnLastDay.CustomerID, Si.ContactID
from
(
select Soh.CustomerID, Soh.ContactID
from Sales.SalesOrderHeader as Soh
where Soh.OrderDate =
(
select MAX(Soh.OrderDate)
from Sales.SalesOrderHeader as Soh
)
) as CustOnLastDay
inner join Sales.Individual as Si
on CustOnLastDay.ContactID = Si.ContactID
order by Si.CustomerID, Si.ContactID
问题 - 哪个更好,只有子查询或加入(一般情况下和这种情况)?
顺便说一句,我的大多数表都没有超过14-15k行。
感谢。
答案 0 :(得分:4)
在JOIN中,RDBMS可以创建一个执行计划,与子查询相比,它更快。在许多情况下,您会发现JOINS比子查询更快。然而,当它们功能相同时,它们将执行相同的操作。子查询加载所有要处理的数据
MSDN说: -
包含子查询的许多Transact-SQL语句都可以 或者配制成连接。其他问题只能提出 用子查询。在Transact-SQL中,通常没有性能 包含子查询和a的语句之间的区别 没有的语义等价版本。但是,在某些情况下 在必须检查存在的情况下,连接会产生更好的性能。 否则,必须为每个结果处理嵌套查询 外部查询以确保消除重复。在这种情况下,加入 方法会产生更好的结果。
例如: -
如果你这样做: -
select * from table1 where exists select * from table2 where table2.parent=table1.id
然后最好使用 JOIN
选中此Example,解释了SUBQUERY和JOIN表现之间的区别: -
USE AdventureWorks
GO
-- use of =
SELECT *
FROM HumanResources.Employee E
WHERE E.EmployeeID = ( SELECT EA.EmployeeID
FROM HumanResources.EmployeeAddress EA
WHERE EA.EmployeeID = E.EmployeeID)
GO
-- use of in
SELECT *
FROM HumanResources.Employee E
WHERE E.EmployeeID IN ( SELECT EA.EmployeeID
FROM HumanResources.EmployeeAddress EA
WHERE EA.EmployeeID = E.EmployeeID)
GO
-- use of exists
SELECT *
FROM HumanResources.Employee E
WHERE EXISTS ( SELECT EA.EmployeeID
FROM HumanResources.EmployeeAddress EA
WHERE EA.EmployeeID = E.EmployeeID)
GO
-- Use of Join
SELECT *
FROM HumanResources.Employee E
INNER JOIN HumanResources.EmployeeAddress EA ON E.EmployeeID = EA.EmployeeID
GO
现在比较执行计划: -
答案 1 :(得分:0)
通常首选连接子查询的多级嵌套。通常,连接速度更快,因为SQL Server Engine可以更好地优化此类查询。
答案 2 :(得分:0)
内部联接通常比子查询更快,因为子查询通常每次都执行,无论当前记录在from子句的第一部分中是什么......
此外,您可以通过将MAX()订单日期作为自己的查询来做得更好,这样就不会在每条记录上完成并加入下游。确保您的订单表头上有索引。我希望它基于(orderdate,customerid),因此它是一个覆盖索引,并且不需要返回原始数据页面以获取其他标准,因为订单日期和客户ID在它可以使用的索引中。
我会将查询修改为......
select
soh2.CustomerID,
si.ContactID
from
( select max( soh.orderdate ) MaxDate
from sales.salesorderheader soh ) as JustDate
join sales.salesorderheader soh2
on JustDate.MaxDate = soh2.OrderDate
join Sales.Individual SI
on soh2.CustomerID = SI.CustomerID
order by
soh2.CustomerID,
si.ContactID
答案 3 :(得分:0)
既不!查看ranking functions的一些灵感。 ANSI SQL调用这些窗口函数。您可能会发现DENSE_RANK()正是您以优雅的方式获取最新日期所需的:
select *
from (
select Si.CustomerID, Si.ContactID,
DENSE_RANK() OVER(ORDER BY soh.OrderDate DESC) as DenseRank
from Sales.Individual Si
inner join SalesOrderHeader soh on soh.CustomerId = Si.CustomerId
) subquery
where subquery.DenseRank = 1