我有一个统计表(仅附加),其活动记录是WordsRead
MinutesRead
UserId
BookId
,UserGroupId
,Date
{}}和MinutesRead
。
现在我想找到自给定日期以来的总PagesRead
和SELECT Minutes = SUM(r.MinutesRead), Pages = SUM(r.PagesRead)
FROM (SELECT DISTINCT r.Date, r.UserId, r.BookId, r.UserGroupId
FROM dbo.ReadingStatDaily r
WHERE r.Date >= @p0) r0
CROSS APPLY (SELECT TOP 1 r.MinutesRead, r.PagesRead
FROM dbo.ReadingStatDaily r
WHERE r0.Date = r.Date AND r0.UserId = r.UserId AND r0.UserGroupId = r.UserGroupId AND r0.BookId = r.BookId
AND r.Date >= @p0
ORDER BY r.WordsRead DESC, r.PagesRead DESC) r
。
此查询正常工作 ...但在较大的日期范围内,它的速度非常慢:
FIRAuth.auth()?.createUserWithEmail
执行计划如下:
没有扫描,关键查找或其他任何悬而未决的成果。
如何从这个查询中获得更好的性能?
答案 0 :(得分:1)
我通过调整索引来优化它。我的线索是72%的查询成本是在那个排序子条款中。索引IX_ReadingStatDaily_User
正在UserId
和{{BookId
上对UserGroupId
,Date
,INCLUDE
和WordsRead
以及PagesRead
建立索引1}}(以及其他一些领域)。我将WordsRead
和PagesRead
移到索引本身,突然查询占用原始时间的三分之一。
答案 1 :(得分:1)
另一种可以重写的方法是
DECLARE @p0 DATE = <what_ever>;
WITH r0
AS (SELECT Date,
UserId,
BookId,
UserGroupId,
MAX(RIGHT(CONCAT('000000000', WordsRead), 10) +
RIGHT(CONCAT('000000000', PagesRead), 10) +
RIGHT(CONCAT('000000000', MinutesRead), 10) COLLATE Latin1_General_BIN2) AS highest_words_pages_minutes
FROM dbo.ReadingStatDaily
WHERE Date >= @p0
GROUP BY Date,
UserId,
BookId,
UserGroupId)
SELECT Minutes = SUM(0 + RIGHT(highest_words_pages_minutes, 10)),
Pages = SUM(0 + SUBSTRING(highest_words_pages_minutes, 11, 10))
FROM r0
哪个应该提供更简单的计划,例如
假设您的索引类似于
CREATE INDEX IX_ReadingStatDaily_User
ON dbo.ReadingStatDaily(Date ASC,
UserId ASC,
BookId ASC,
UserGroupId ASC)
INCLUDE (WordsRead, PagesRead, MinutesRead)
答案 2 :(得分:0)
这样的事情会起作用吗?
select Minutes = SUM(r.MinutesRead), Pages = SUM(r.PagesRead) from (
SELECT
Date,
UserId,
BookId,
UserGroupId,
MinutesRead,
PagesRead,
row_number() over (PARTITION BY Date, r.UserId, r.BookId, r.UserGroupId
ORDER BY r.WordsRead DESC, r.PagesRead DESC) as RN
FROM
dbo.ReadingStatDaily
WHERE
Date >= @p0
) X where RN = 1