2015-02-24 2 views
3

Я использую этот запрос для выборки ранга пользователя из Sql Server БДА:Оптимизировать ранг запрос

select user_rank 
from (select t.user_id, rank() over (order by score desc) as user_rank 
    from user_stats t 
) t 
where t.user_id='some_user_id'; 

таблица состоит около 22000 строк и запрос занимает 3,5 секунды, что является слишком медленным.

Есть несколько индексов на этой таблице, это соответствующая:

user_id - уникальный, NONCLUSTERED INDEX

счет - Неуникальная, NONCLUSTERED INDEX

Если изменить идентификатор запроса и использования (который является моим первичным ключом) вместо user_id, то запрос выполняется быстро:

select user_rank 
from (select t.id, rank() over (order by score desc) as user_rank 
    from user_stats t 
) t 
where t.id='some_id'; 

После проверки плана выполнения я вижу, что стоимость сканирования кластеризованного индекса составляет 92%, хотя я не понимаю, почему это необходимо в этом случае.

Что можно сделать для оптимизации этого запроса?

Статистика запроса:

SQL-сервера и разбора во время компиляции: процессорного времени = 0 мс, прошло время = 0 мс.

Время выполнения SQL Server: время процессора = 0 мс, прошедшее время = 0 мс. Время и время компиляции SQL Server: время процессора = 0 мс, прошедшее время = 0 мс.

Время выполнения SQL Server: время процессора = 0 мс, прошедшее время = 0 мс. Время и время компиляции SQL Server: время процессора = 0 мс, прошедшее время = 0 мс.

Время выполнения SQL Server: время процессора = 0 мс, прошедшее время = 0 мс. Время и время компиляции SQL Server: время процессора = 0 мс, прошедшее время = 0 мс.

(1 ряд (-ых) затронутых) Таблица 'users_stats'. Количество сканирования 1, логический считывает 22529, физических чтений 0, упреждающего чтения читает 0, Лоб логического чтения 0, Лоб физической читает 0, лоб упреждающего чтения читает 0.

(1 строку (ы) пострадавших)

Время выполнения SQL Server: время процессора = 78 мс, прошедшее время = 3576 мс. Время и время компиляции SQL Server: время CPU = 0 мс, прошедшее время = 0 мс.

Время выполнения SQL Server: время процессора = 0 мс, прошедшее время = 0 мс.

+0

Вы собираетесь не иметь развертку здесь, независимо от того, что, потому что ваш подзапрос должен смотреть на каждую строку таблицы. Не уверен, почему это будет 3,5 секунды, но без определения таблиц и индексов это только предположение. –

+0

Если идентификатор пользователя уникален, то какова цель ранжирования одного пользователя? –

+0

Но почему существует такая разница между использованием user_id и id, поскольку они оба индексируются? –

ответ

1

Я подозреваю, что основной причиной ухудшения вашей производительности является то, что ваш индекс не покрывает. Вероятнее всего, вы увидите существенное улучшение производительности, за счет покрытия индекса. Here - хорошая статья, в которой обсуждаются индексы покрытия.

Вкратце, индекс предлагает просто указатель на строку.Чтобы получить данные для столбца «оценка», который необходим для ранжирования набора результатов, движок должен сканировать кластерный индекс для поиска данных. Если вы включите значение в индекс, двигатель сможет выполнить операцию без необходимости сканирования кластерного индекса.

Индекс должен быть переписан следующим образом:

CREATE UNIQUE NONCLUSTERED ИНДЕКС UQ_USER_STATS_USER_ID ПО user_stats (идентификатор_пользователь) Include (счет);

0

Вместо

select user_rank 
from (select t.id, rank() over (order by score desc) as user_rank 
    from user_stats t 
) t 
where t.id='some_id'; 

насчет

with t as (
    select t.user_id, 
    ROW_NUMBER() as user_rank 
    from user_stats t 
    order by score desc 
) 
select user_rank 
from t 
where t.id='some_id'; 
Смежные вопросы