【问题标题】:Group by, Order by, sub queries - Performance Problem for getting the previous row valueGroup by、Order by、子查询 - 获取前一行值的性能问题
【发布时间】:2026-02-08 20:15:01
【问题描述】:

我正在使用 MS ACCESS 2003

表名 –> tmp_cardevent

PERSONID   CARDEVENTDATE  CARDEVENTTIME

5008       20090805       080000
5008       20090805       140000
5008       20090809       180000
5008       20090809       220000
3405       20090805       080000
3405       20090805       180000
3405       20090809       070000
3405       20090809       230000
3010       20080806       090000
3010       20080806       230000
3010       20080810       100000
3010       20080810       160000

我想为人员 ID 显示今天时间和前一天时间 前一天表示不是昨天,特定人员 ID 的前一个 cardeventtime。

我进行以下查询以获取上一行的值

select t1.Personid, 
    t1.cardeventdate, 
    t1.cardeventtime, 
    t2.Personid,  
    t2.cardeventdate,
    t2.cardeventtime 
from  tmp_cardevent  t1 inner join tmp_cardevent t2 on t1.cardno = t2.cardno 
where t2.cardeventdate =  (
    select max(cardeventdate)  
    from tmp_cardevent ds 
    where ds.cardeventdate < t1.cardeventdate
        and ds.cardno = t1.cardno 
    ) 

从上面的查询中,上一行显示完美

预期输出

PERSONID   CARDEVENTDATE      LastCARDEVENTDATE  

5008       20090809           20090805       
3405       20090809           20090805       
3010       20080810           20080806     

但是如果在上面的查询中使用group by,order by,子查询,那么它会花费很长时间没有显示,因为它在大量数据中的性能非常糟糕

那么任何人都可以帮助我为此类问题找到最佳解决方案吗?

或任何其他查询帮助?

【问题讨论】:

  • 考虑到提供的样本数据,预期的输出是什么?
  • 另外,您在查询中的哪个位置指定了今天的日期?您是否尝试获取所有人的所有记录以及他们之前的交易时间?
  • 我添加了我的预期输出,是的,我想获取 personid 的所有当前行日期、上一行日期

标签: ms-access sql-server-2000


【解决方案1】:
SELECT
   Seq = identity(int, 1, 1),
   CardNo,
   CardEventDate
INTO #CardSeq
FROM tmp_cardevent
ORDER BY CardNo, CardEventDate

SELECT
   t1.Personid,
   t1.cardeventdate,
   t1.cardeventtime,
   t2.Personid,
   t2.cardeventdate,
   t2.cardeventtime
from
   tmp_cardevent t1
   inner join #CardSeq S1 ON t1.CardNo = S.CardNo
   left join #CardSeq S2 ON t1.CardNo = t2.CardNo and t1.Seq - 1 = t2.Seq
   left join tmp_cardevent t2 on t1.cardno = t2.cardno

DROP TABLE #CardSeq

在 CardNo 和/或 Seq 上的临时表上放置索引应该会有所帮助。在填充之前使用索引创建临时表可能比在使用 SELECT INTO 之后添加索引更好。试验只在每一列上使用聚簇索引,然后在一个列上聚簇 + 在另一列上非聚簇,反之亦然,看看什么能提供最佳性能。

如果您在查询中有限制卡号的条件,请在插入临时表时执行此操作,以便它仅在必要时起作用。

需要左连接,否则第一个事件永远不会出现。

【讨论】:

    【解决方案2】:

    您需要在分组和有序列上建立索引。

    例如在 Customer 表中的 Last_Name 列上创建索引。 创建索引 IDX_CUSTOMER_LAST_NAME 关于客户(姓氏)

    同样,您可以在 group by 和 order 子句中使用的列上创建索引。

    【讨论】:

    • 编辑了我的答案。请检查。