Rebus SqlServerTransport,来自 SQL 服务器的 "MissingIndex" 似乎不正确,或者某些东西没有按预期工作

Rebus SqlServerTransport, "MissingIndex" from SQL Server seems incorrect, or something isn't working as intended

SQL 服务器报告 RebusSQLServerTransport 使用的消息 table 需要为其创建不同的索引。我觉得当前的索引设置是正确的,但是 CTE 的使用、删除和输出导致 SQL 服务器执行某些操作。

是 SQL 服务器在索引上出错还是 CTE 在这里做了一些意外的事情?

SQL 服务器正在请求和索引

CREATE INDEX IX_<NewNameHere> 
ON [MessageQueues].[dbo].[Messages] ([id]) 
INCLUDE ([recipient], [priority])

目前聚集索引在哪里

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]

这是针对此数据库的唯一查询 运行。

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'

更新: 我在导致所需索引的查询上错了。 Rebus 定期发送消息 PerformExpiredMessagesCleanupCycle 运行此查询

``` 从 [{_tableName}] 中删除 其中 [id] 在 ( SELECT TOP 1 [id] 来自 [{_tableName}] WITH (ROWLOCK, REDPAST) WHERE [收件人] = @recipient AND [过期时间] < getdate() )

```

是所需索引的来源。

"SQL Server is reporting that (...) needing a different index" 是什么意思?你在哪里看到的?

我不是 SQL 服务器方面的专家....但是当我通过使用 Rebus 自动创建的索引在 table 上执行查询获得实际查询计划时,我得到这个计划:

现在,由于我不是专家,所以当我看这些东西时,我可能会遗漏很多东西。但我知道要注意的是 "index scan",而 "index seek" 很好,因为这意味着 SQL 服务器实际上正在使用索引。


为了检查 SQL 服务器建议的索引是否会产生影响,我进行了一项测试,测量端点接收 10000 条消息所花费的时间。

在第一轮中,测试以通常的配置运行 - 即 没有 SQL 服务器建议的索引:

10000 messages received in 12,5 s - that's 801,5 msg/s

第二轮,我添加SQL服务器建议的索引:

10000 messages received in 13,6 s - that's 736,2 msg/s

在第三轮中,我添加了 SQL 服务器建议的索引,并删除了 Rebus 自己创建的索引:

10000 messages received in 13,8 s - that's 722,6 msg/s

这里是用一个简洁的小 ASCII 码总结的结果 table:

+---------------+-----------+----------------------+
| Current index | New index | Approx. receive rate |
+---------------+-----------+----------------------+
|      Yes      |    No     |      800 msg/s       |
|      Yes      |    Yes    |      735 msg/s       |
|      No       |    Yes    |      720 msg/s       |
+---------------+-----------+----------------------+

据此-当然,不是很彻底,但可能足够指示-测试,如果使用SQL服务器建议的索引,似乎不会提高接收率。

Rebus 为每个队列定期清理以删除所有过期消息。它做到了这一点 command.CommandText =$@" DELETE FROM [{_tableName}] WHERE [id] IN ( AND [expiration] < getdate() ) ";

如果查询是这样的 command.CommandText =$@" ;with TopCTE as ( SELECT TOP 1 [id] FROM [{_tableName}] WITH (ROWLOCK, READPAST) WHERE [recipient] = @recipient AND [expiration] < getdate() ) DELETE FROM TopCTE "; 那么就不需要进行导致 ID 列被扫描的二次查找。