SQL Server is reporting that the Messages table used by Rebus
and it's SQLServerTransport
are needing a different index created for it. I feel the current index setup is correct, but something about the usage of a CTE, deleting, and outputting is causing SQL Server to do something.
Is SQL Server wrong on the index or is the CTE doing something unexpected here?
SQL Server is requesting and index along the lines of
CREATE INDEX IX_<NewNameHere>
ON [MessageQueues].[dbo].[Messages] ([id])
INCLUDE ([recipient], [priority])
where are currently the clustered index is like
PRIMARY KEY CLUSTERED
(
[recipient] ASC,
[priority] ASC,
[id] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
and here is the only query being ran against this DB.
exec sp_executesql N'SET NOCOUNT ON
;WITH TopCTE AS
(
SELECT TOP 1
[id], [headers], [body]
FROM
[Messages] M WITH (ROWLOCK, READPAST)
WHERE
M.[recipient] = @recipient
AND M.[visible] < getdate()
AND M.[expiration] > getdate()
ORDER BY
[priority] ASC, [id] ASC
)
DELETE FROM TopCTE
OUTPUT deleted.[id] as [id],
deleted.[headers] as [headers],
deleted.[body] as [body]
', N'@recipient nvarchar(200)', @recipient=N'Location'
Update:
I was wrong on the query that was causing the wanted index. Rebus does a periodic message PerformExpiredMessagesCleanupCycle
which runs this query
``` DELETE FROM [{_tableName}] WHERE [id] IN ( SELECT TOP 1 [id] FROM [{_tableName}] WITH (ROWLOCK, READPAST) WHERE [recipient] = @recipient AND [expiration] < getdate() )
```
is where the wanted index is coming from.
Rebus, for each queue, does a periodic clean up to delete all expired messages. It did this
command.CommandText =$@"
DELETE FROM [{_tableName}]
WHERE [id] IN (
AND [expiration] < getdate()
)
";
If the query was like this
command.CommandText =$@"
;with TopCTE as (
SELECT TOP 1 [id] FROM [{_tableName}] WITH (ROWLOCK, READPAST)
WHERE [recipient] = @recipient
AND [expiration] < getdate()
)
DELETE FROM TopCTE
";
then there wouldn't be a need to do the secondary lookup which is causing the ID
column to be scanned.