I have a table that stores transactions for accounts, and I want to select out the latest transaction for a specific account. But the DB (Azure SQL) seems to fetch all transactions for the account, and then do top 1 when I order the result on two columns, and I dont understand why.
My query looks something like this:
SELECT TOP 1 *
FROM [dbo].[Transaction] T
WHERE T.AccountId = 4
ORDER BY
T.[Timestamp] DESC,
T.[Created] DESC
and plan: https://www.brentozar.com/pastetheplan/?id=SyF7Y2ew2
If I instead just order on Timestamp it does it quicker:
SELECT TOP 1 *
FROM [dbo].[Transaction] T
WHERE T.AccountId = 4
ORDER BY
T.[Timestamp] DESC
https://www.brentozar.com/pastetheplan/?id=HJDqFhgD3
The table and index:
CREATE TABLE [dbo].[Transaction](
[TransactionId] [UNIQUEIDENTIFIER] NOT NULL PRIMARY KEY,
[Created] [DATETIME] NOT NULL DEFAULT GETUTCDATE(),
[Timestamp] [DATETIME] NOT NULL,
[AccountId] int NULL)
GO
CREATE NONCLUSTERED INDEX [IX_Transaction_AccountId_Timestamp] ON [dbo].[Transaction]([AccountId], [Timestamp] DESC) WITH (ONLINE = ON)
GO
I have simplified the query and table a bit for testing purposes. In my real table I have 10s of millions of rows, with quite a lot of columns not included here, but the behavior regarding the query plan usage is the same.
Created
is not part of the index thereby introducing more work (sorting specifically) for the database to do. You can see that directly in the explain plan as the first one includes a Top N Sort node that the latter does not Create an index with that column appended at the end and it should speed things upTimestamp
first, so why does it need to also checkCreated
? In my actual query its ordering on 3 columns, where the first (Timestamp
) will be enough for more or less 99.99% of cases and only when theres a duplicate its adding the second level ordering.Timestamp
value. I don't know SQL Server well enough to say, but broadly I know that not all databases support such an operation. Looking forward to seeing what SQL Server experts might say and/or if there is a rewrite that could achieve similar results. That's assuming you won't create the other index though since that would solve the problem too