У меня есть схема таблицы, аналогичная следующей (упрощенной):
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
не обязательно является самой последней транзакцией.
На самом деле самая последняя транзакция представляет собой комбинацию даты и идентификатора. Даты не уникальны - поставщик часто усекает время дня - поэтому, чтобы получить самую последнюю транзакцию, я должен сначала найти самую последнюю дату, а затем найти самый последний идентификатор для этой даты.
Я знаю, что могу сделать это с помощью оконного запроса (ROW_NUMBER() OVER (PARTITION BY TransactionDate DESC, TransactionID DESC)
), но для этого требуется полное сканирование индекса и очень дорогая сортировка, и, таким образом, он терпит неудачу с точки зрения эффективности. Также довольно неловко продолжать писать все время.
Немного эффективнее использовать два CTE или вложенных подзапроса, один для поиска MAX(TransactionDate)
на CustomerID
, а другой для поиска MAX(TransactionID)
. Опять же, это работает, но требует второго агрегата и объединения, что немного лучше, чем запрос ROW_NUMBER()
, но все же довольно болезненно с точки зрения производительности.
Я также рассмотрел вопрос об использовании пользовательского агрегата CLR и в случае необходимости остановлюсь на этом, но я бы предпочел найти решение на чистом SQL, если это возможно, чтобы упростить развертывание (где-то нет необходимости в SQL-CLR остальное в этом проекте).
Итак, вопрос, в частности:
Можно ли написать запрос, который будет возвращать новейший TransactionID
за CustomerID
, определенный как максимальный TransactionID
для самого последнего TransactionDate
, и достичь План эквивалентен по производительности обычному MAX
/ GROUP BY
запросу?
(Другими словами, единственными значительными шагами в плане должны быть сканирование индекса и объединение потоков. Многократные сканирования, сортировки, объединения и т. Д., Вероятно, будут слишком медленными.)