Я создаю таблицу лидеров для некоторых своих онлайн-игр. Вот что мне нужно сделать с данными:
- Получить ранг игрока за заданную игру за несколько временных рамок (сегодня, на прошлой неделе, все время и т.д.).
- Получить рейтинг с разбивкой по страницам (например, верхний балл за последние 24 часа, получить игроков между рангами 25 и 50, получить ранг или одного пользователя).
Я определил следующее определение таблицы и индекса, и у меня есть несколько вопросов.
Учитывая мои сценарии, у меня есть хороший первичный ключ? Причина, по которой у меня есть кластерный ключ в gameId, playerName и оценка, просто потому, что я хочу убедиться, что все данные для данного игра находится в той же области, и этот счет уже отсортирован. В большинстве случаев я покажу данные по убыванию счета (+ updatedDateTime для связей) для данного gameId. Это правильная стратегия? Другими словами, я хочу убедиться, что я могу запускать свои запросы, чтобы как можно быстрее получить ранг моих игроков.
CREATE TABLE score (
[gameId] [smallint] NOT NULL,
[playerName] [nvarchar](50) NOT NULL,
[score] [int] NOT NULL,
[createdDateTime] [datetime2](3) NOT NULL,
[updatedDateTime] [datetime2](3) NOT NULL,
PRIMARY KEY CLUSTERED ([gameId] ASC, [playerName] ASC, [score] DESC, [updatedDateTime] ASC)
CREATE NONCLUSTERED INDEX [Score_Idx] ON score ([gameId] ASC, [score] DESC, [updatedDateTime] ASC) INCLUDE ([playerName])
Ниже приведена первая итерация запроса, который я буду использовать, чтобы получить ранг моих игроков. Однако я немного разочарован планом исполнения (см. Ниже). Почему SQL должен сортироваться?. Дополнительная сортировка, похоже, поступает из функции RANK. Но разве мои данные уже отсортированы в порядке убывания (на основе кластеризованного ключа таблицы баллов)? Мне также интересно, нужно ли мне нормализовать немного больше моей таблицы и вывести столбец PlayerName в таблицу Player. Первоначально я решил сохранить все в одной таблице, чтобы свести к минимуму количество объединений.
DECLARE @GameId AS INT = 0
DECLARE @From AS DATETIME2(3) = '2013-10-01'
SELECT DENSE_RANK() OVER (ORDER BY Score DESC), s.PlayerName, s.Score, s.CountryCode, s.updatedDateTime
FROM [mrgleaderboard].[score] s
WHERE s.GameId = @GameId
AND (s.UpdatedDateTime >= @From OR @From IS NULL)
Спасибо за помощь!