2

我在 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 子句 OR 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。

谢谢。

4

4 回答 4

4

在 JOIN 中,RDBMS 可以创建一个执行计划,这使得它比子查询更快。在许多情况下,您会发现 JOINS 比子查询要快。但是,当它们在功能上等效时,它们将执行相同的操作。子查询加载所有数据进行处理

MSDN说:-

许多包含子查询的 Transact-SQL 语句可以替代地表述为连接。其他问题只能通过子查询提出。在 Transact-SQL 中,包含子查询的语句与不包含子查询的语义等效版本之间通常没有性能差异。但是,在某些必须检查存在性的情况下,连接会产生更好的性能。否则,必须为外部查询的每个结果处理嵌套查询,以确保消除重复。在这种情况下,连接方法会产生更好的结果。

例如:-

如果你正在做这样的事情: -

select * from table1 where exists select * from table2 where table2.parent=table1.id

那么最好使用JOIN

检查此示例,它解释了 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

现在比较执行计划:-

在此处输入图像描述

于 2013-09-18T20:34:44.310 回答
0

连接通常比带有子查询的多级嵌套更受欢迎。一般来说,连接速度更快,因为 SQL 服务器引擎可以更好地优化这种类型的查询。

于 2013-09-18T20:39:55.723 回答
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
于 2013-09-18T20:45:27.380 回答
0

两者都不!查看排名功能以获得一些灵感。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 
于 2013-09-18T20:50:01.783 回答