哪个更好 - 只有子查询或加入?

时间:2013-09-18 20:29:37

标签: sql sql-server join subquery

我在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行。

感谢。

4 个答案:

答案 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

现在比较执行计划: -

enter image description here

答案 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