Tim*_*hel 9 performance sql-server ssms query-performance
过去几天我一直在搜索、观看视频,我想我已经尽可能地摸索了。给出我下面的例子,我正在寻找更具体的方向。
我有两张桌子正在处理。MessageThreads(400k 条记录)和 Messages(1M 条记录)。它们的模式如下所示。
消息线程索引
https://gist.github.com/timgabrhel/0a9ff88160ebc9e40559e1e10ecc7ee4
消息索引
https://gist.github.com/timgabrhel/d649074cbe82016e8a90f918c58c4764
我正在尝试提高我们的主要“收件箱”查询的性能。想想您的电子邮件提供商的收件箱。您将看到一个线程列表,一些是新的,一些是已读的,按日期排序,还可以预览最近发送的消息,无论是发送给您还是来自您。最后,这个查询有一个分页元素。默认情况下,我们需要 11 个项目。10 用于显示页面,+1 以了解下一页是否还有更多内容。
对于我们的一些长期用户,他们最多可以拥有 40K 条消息。
在过去的几天里,这个查询出现了许多不同的形式,但这就是我所了解的。我已经OUTER APPLY试过了,但我看到执行时间和统计数据更糟。
SET STATISTICS IO ON; /* And turn on the Actual Excecution Plan */
declare @UserId bigint
set @UserId = 9999
; WITH cte AS (
SELECT
ROW_NUMBER() OVER (ORDER BY SendDate DESC) AS RowNum,
MT.MessageThreadId,
MT.FromUserHasArchived,
MT.ToUserHasArchived,
MT.Created,
MT.ThreadStartedBy,
MT.ThreadSentTo,
MT.[Subject],
MT.CanReply,
MT.FromUserDeleted,
MT.ToUserDeleted,
LM.MessageId,
LM.Deleted,
LM.FromUserId,
LM.ToUserId,
LM.[Message],
LM.SendDate,
LM.ReadDate
FROM MessageThreads MT
-- join the most recent non-deleted message where this user is the sender or receiver
LEFT OUTER JOIN
(
SELECT RANK() OVER (PARTITION BY MessageThreadId ORDER BY SendDate DESC) r, *
FROM [Messages]
WHERE (FromUserId=@UserId OR ToUserId=@UserId)
AND (Deleted=0)
) LM ON (LM.MessageThreadId = MT.MessageThreadId AND LM.r = 1)
--WHERE MT.ThreadSentTo=@UserId OR MT.ThreadStartedBy=@UserId
)
SELECT
cte.*,
UserFrom.FirstName AS UserFromFirstName,
UserFrom.LastName AS UserFromLastName,
UserFrom.Email AS UserFromEmail,
UserTo.FirstName AS UserToFirstName,
UserTo.LastName AS UserToLastName,
UserTo.Email AS UserToEmail
FROM cte
LEFT OUTER JOIN Users AS UserFrom ON cte.FromUserId=UserFrom.UserId
LEFT OUTER JOIN Users AS UserTo ON cte.ToUserId=UserTo.UserId
WHERE RowNum >= 1
AND RowNum <= 11
ORDER BY RowNum ASC
Run Code Online (Sandbox Code Playgroud)
上述查询的统计信息(SSMS 中的执行时间约 2 秒)。这个执行时间是可以接受的,但统计数据感觉不太理想,在查看实际执行计划时更是如此。

执行计划链接在这里 https://gist.github.com/timgabrhel/f8d919d5728e965623fbd953f7a219ef
我发现的一个大问题是 MessageThreads 表上的 400k 行索引扫描。大概这是因为主SELECT X FROM MessageThreads查询没有过滤器。当我对其应用谓词时(从查询中取消注释 WHERE),统计数据大大改善(如下),但时间在 SSMS 中从 ~2 秒跳到 ~18 秒。
查询上的问题区域是 MessageThreads 谓词
https://gist.github.com/timgabrhel/1383ff9362567fdf41ba011dead63ceb
先感谢您!
一些想法:
WHERE MT.ThreadSentTo=@UserId OR MT.ThreadStartedBy=@UserId实际上需要两个索引才能高效 - 一个位于 ThreadSentTo 字段,另一个位于 ThreadStartedBy 字段。否则,SQL 引擎将执行全表扫描以检索正确的线程。
从 SQL 2012 开始,SQL Server 添加了一个新的构造来处理分页。这工作起来是这样的:
DECLARE @PageNumber int = 20
DECLARE @RowsPerPage int = 15
SELECT *
FROM MyTable T
INNER JOIN MyDetailTable D
ON T.MyTableID = D.MyTableID
OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
FETCH NEXT @RowsPerPage ROWS ONLY
Run Code Online (Sandbox Code Playgroud)
在这种情况下,查询将跳过前 285 ((20-1)*15) 行,并检索接下来的 15 行。对于正常分页,这是比旧的 RowNumber() 过滤器更快的分页方法。
| 归档时间: |
|
| 查看次数: |
463 次 |
| 最近记录: |