SQL 服务器中的游标:高性能惩罚

Cursors in SQL Server: High Performance Penalty

调用表

CallId |    Date | Time |   MemberID |  CallDuration
12     |    02.02.2015| 13:33:54|   3245|   234 |
13     |    02.02.2015| 13:37:24|   3245|   33  |

ActivityTable

Date*********** Time*** MemberId    ***Activity
02.02.2015***   13:31:22*** 3245*** A
02.02.2015***   13:34:54*** 3245*** B

我的老板想知道 activity 成员(员工)在收到 phone 打电话。此数据存储在上面给出的两个表中。

我正在使用 Cursor 从 CallTable 获取每一行,然后在循环中使用另一个游标来检索最后一个 activity。 CallTable 中大约有 100 万行,处理它需要很长时间。 CallTable中没有基于CallID的Primary-Foreign key关系。

这里有人可以建议我如何通过 JOIN 实现此目的并避免使用游标吗?

提前致谢

在 SQL 服务器中,您可以使用相关子查询或使用 APPLY 来执行此操作。例如:

select c.*, a.activity
from calltable c outer apply
     (select top 1 a.*
      from activitytable a
      where a.memberId = c.memberId and
            a.datetime <= c.datetime
      order by a.datetime asc
     ) a;

这假定 date/time 在同一列中,这将是存储此值的正确方法。如果它们在不同的列中,则类似(但更复杂)的逻辑有效。

为了性能,您需要 activitytable(memberid, datetime) 上的索引。

滞后和超前可能对您有所帮助

http://blog.sqlauthority.com/2013/09/22/sql-server-how-to-access-the-previous-row-and-next-row-value-in-select-statement/

这是一个 Northwind 迷你示例。

select * , DaysSincePreviousOrder = datediff(d , PreviousValue, OrderDate)  from (

  SELECT
LAG(p.OrderDate) OVER (ORDER BY p.CustomerID, p.OrderDate) PreviousValue,
p.CustomerID, p.OrderDate,
LEAD(p.OrderDate) OVER (ORDER BY p.CustomerID , p.OrderDate) NextValue
FROM dbo.Orders p where CustomerID = 'anatr' ) as derived1
where derived1.OrderDate = (select max(OrderDate) from dbo.Orders o where o.CustomerID = derived1.CustomerID)

GO

99.9% 的事情都可以在没有光标的情况下完成。我在 10 年内编写了一个游标......并且没有重新访问它以查看是否可以重构。 我认为这是 "hit several database" 类型的事情。但这是规则的微小例外......继续追求 "set based" 和非游标解决方案。