我有一个类似于以下(简化)的表模式:
CREATE TABLE Transactions
(
TransactionID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
CustomerID int NOT NULL, -- Foreign key, not shown
TransactionDate datetime NOT NULL,
...
)
CREATE INDEX IX_Transactions_Customer_Date
ON Transactions (CustomerID, TransactionDate)
在这里提供一些背景知识,这个事务表实际上是合并了来自另一个供应商数据库的几种不同类型的事务(我们将其称为 ETL 过程),因此我对他们被插入。即使我这样做了,交易也可能是回溯的,所以这里要注意的重要一点是,任何给定的最大值不一定是最近的交易。TransactionID
customer
事实上,最近的交易是日期和ID 的组合。日期不是唯一的 - 供应商经常截断一天中的时间 - 所以要获得最近的交易,我必须首先找到最近的日期,然后找到该日期的最新 ID。
我知道我可以使用窗口查询ROW_NUMBER() OVER (PARTITION BY TransactionDate DESC, TransactionID DESC)
(一直写下去也很尴尬。
稍微高效的是使用两个 CTE 或嵌套子查询,一个用于查找MAX(TransactionDate)
per CustomerID
,另一个用于查找MAX(TransactionID)
. 再次,它可以工作,但需要第二次聚合和连接,这比查询稍好,ROW_NUMBER()
但在性能方面仍然相当痛苦。
我也考虑过使用 CLR 用户定义的聚合,如果有必要,我会依赖它,但如果可能的话,我更愿意找到一个纯 SQL 解决方案来简化部署(在此其他任何地方都不需要 SQL-CLR项目)。
所以这个问题,具体来说是:
是否可以编写一个查询来返回最新 TransactionID
的per CustomerID
,定义为TransactionID
最近的最大值TransactionDate
,并实现与普通MAX
/GROUP BY
查询等效的计划?
(换句话说,计划中唯一重要的步骤应该是索引扫描和流聚合。多次扫描、排序、连接等可能太慢了。)