sql-server - 在 SQL 中获取运行总计最大值的高性能方法

标签 sql-server tsql sql-server-2008 sql-server-2000

我们有一个交易表,其结构如下:

TranxID    int (PK and Identity field)
ItemID     int
TranxDate  datetime
TranxAmt   money

TranxAmt 可以是正数或负数,因此该字段的运行总数(对于任何 ItemID)将随着时间的推移而上下波动。获取当前总数显然很简单,但我所追求的是一种在发生这种情况时获取运行总数和 TranxDate 最大值的高性能方法。请注意,TranxDate 不是唯一的,并且由于某些回溯日期,ID 字段不一定与给定项目的 TranxDate 具有相同的顺序。
目前我们正在做这样的事情(@tblTranx 是一个表变量,只包含给定项目的交易):
SELECT Top 1 @HighestTotal = z.TotalToDate, @DateHighest = z.TranxDate
FROM
    (SELECT a.TranxDate, a.TranxID, Sum(b.TranxAmt) AS TotalToDate
    FROM @tblTranx AS a
    INNER JOIN @tblTranx AS b ON a.TranxDate >= b.TranxDate
    GROUP BY a.TranxDate, a.TranxID) AS z
ORDER BY z.TotalToDate DESC

(TranxID 分组消除了由重复日期值引起的问题)

对于一个项目,这为我们提供了发生这种情况时的 HighestTotal 和 TranxDate。我们不会针对数以万计的条目即时运行该程序,而是仅在应用更新相关条目时计算该值,并将该值记录在另一个表中以用于报告。

问题是,这是否可以以更好的方式完成,以便我们可以动态计算出这些值(同时针对多个项目)而不会落入 RBAR 陷阱(某些 ItemID 有数百个条目)。如果是这样,那么是否可以对其进行调整以获得事务子集的最高值(基于上面未包含的 TransactionTypeID)。我目前正在使用 SQL Server 2000 执行此操作,但 SQL Server 2008 将很快在这里接管,因此可以使用任何 SQL Server 技巧。

最佳答案

SQL Server计算运行总数很糟糕。

这是您的查询的解决方案(按日期分组):

WITH    q AS
        (
        SELECT  TranxDate, SUM(TranxAmt) AS TranxSum
        FROM    t_transaction
        GROUP BY
                TranxDate
        ),
        m (TranxDate, TranxSum) AS
        (
        SELECT  MIN(TranxDate), SUM(TranxAmt)
        FROM    (
                SELECT  TOP 1 WITH TIES *
                FROM    t_transaction
                ORDER BY
                        TranxDate
                ) q
        UNION ALL
        SELECT  DATEADD(day, 1, m.TranxDate),
                m.TranxSum + q.TranxSum
        FROM    m
        CROSS APPLY
                (
                SELECT  TranxSum
                FROM    q
                WHERE   q.TranxDate = DATEADD(day, 1, m.TranxDate) 
                ) q
        WHERE   m.TranxDate <= GETDATE()
        )
SELECT  TOP 1 *
FROM    m
ORDER BY
        TranxSum DESC
OPTION (MAXRECURSION 0)

您需要在 TranxDate 上建立索引为了这个工作快速。

关于sql-server - 在 SQL 中获取运行总计最大值的高性能方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2118829/

相关文章:

sql - 检查时间范围重叠,watchman 问题 [SQL]

sql - 这个 SQL 语句背后的含义是什么? ISNULL(状态,0) & 128 = 0?

sql - 计算两个日期之间的工作日

c# - Linq Where 比 SQL Where 快得多

sql - 将 SQL Server 版本号与名称相关联

sql-server - 无法解决等于操作中 "SQL_Latin1_General_CP1_CI_AS"和 "Latin1_General_CI_AS"之间的排序规则冲突

sql-server - 如何使用 dd-MMM-yyyy 格式将日期时间格式化为 varchar?

java - 将 Java 与 SQL Express 连接起来

SQL Server 2008存储过程结果作为列默认值

c# - 使用 SQL 存储过程和 C# 读取大量数据 (SQL Server 2005)