Проблема в том, что в таблице, похоже, нет индексов, которые были бы полезны для этого.Мы получаем планы выполнения, такие как:
- Сканирование индекса неоптимально.Нам нужен индексный поиск.
Тем не менее, вы можете сократить время почти вдвое:
- Предварительный выбор значков пользователя.
- Использование коррелированного подзапроса для ранга.
- Использование
Id
в качестве прокси для Date
.(Id
s уникальны, увеличиваются и часто быстрее сортируются.)
Также обратите внимание:
- Использование параметра magic
##UserId:INT##
. - В столбце
Class
имеется только 3 значения. - Вы можете сократить время запроса еще на несколько секунд, пропустив предложение
ORDER BY
.
В любом случае, этот запрос работает лучше:
WITH zUsersBadges AS (
SELECT b.Id
, b.UserId
, b.Name
, b.Date
, b.Class
, [Badge Class] = (
CASE WHEN b.Class = 1 THEN 'Gold'
WHEN b.Class = 2 THEN 'Silver'
WHEN b.Class = 3 THEN 'Bronze'
END
)
, [Is tag badge] = IIF (b.TagBased = 1, 'Yes', 'No')
FROM Badges b
WHERE b.UserId = ##UserId:INT##
)
SELECT ub.Name AS [Badge Name]
, ub.[Badge Class]
, ub.[Is tag badge]
, ub.Date AS [Date Earned]
, [In Top N of earners] = (
SELECT COUNT (ob.ID)
FROM Badges ob
WHERE (ob.Name = ub.Name AND ob.Class = ub.Class AND ob.Id <= Ub.Id) -- Faster but may give slightly higher rank
--WHERE (ob.Name = ub.Name AND ob.Class = ub.Class AND ob.Date <= Ub.Date) -- Slower, but gives exact rank.
)
FROM zUsersBadges ub
ORDER BY ub.Name, ub.Date
Обновление: Этот запрос работает еще лучшепотому что он объединяет многократно заработанные значки:
WITH zUsersBadges AS (
SELECT b.UserId
, b.Name
, minId = MIN (b.Id)
, [First Earned] = MIN (b.Date)
, [Earned N times] = COUNT (b.Date)
, b.Class
, [Badge Class] = (
CASE WHEN b.Class = 1 THEN 'Gold'
WHEN b.Class = 2 THEN 'Silver'
WHEN b.Class = 3 THEN 'Bronze'
END
)
, [Is tag badge] = IIF (b.TagBased = 1, 'Yes', 'No')
FROM Badges b
WHERE b.UserId = ##UserId:INT##
GROUP BY b.UserId, b.Class, b.Name, b.TagBased
)
SELECT ub.Name AS [Badge Name]
, ub.[Badge Class]
, ub.[Is tag badge]
, ub.[First Earned]
, ub.[Earned N times]
, [In Top N of earners] = (
SELECT COUNT (ob.ID)
FROM Badges ob
WHERE (ob.Class = ub.Class AND ob.Id <= Ub.minId AND ob.Name = ub.Name) -- Faster but may give slightly higher rank
--WHERE (ob.Class = ub.Class AND ob.Date <= Ub.[First Earned] AND ob.Name = ub.Name) -- Faster but may give slightly higher rank
)
FROM zUsersBadges ub
ORDER BY ub.Name, ub.[First Earned]