2014-02-02 5 views
0

У меня есть эта таблица:Индексация снизить стоимость СНП

TopScores

Username char(255) 
Score int 
DateAdded datetime2 

, который будет иметь много строк.

Я выполнить следующий запрос (код хранимой процедуры) против него, чтобы получить лучшие 5 высоких показателей и оценку для конкретного Имени пользователя, которому предшествует человек непосредственно над ними в положении, и человек ниже:

WITH Rankings 
    AS (SELECT Row_Number() OVER (ORDER BY Score DESC, DateAdded DESC) AS Pos, 
       --if score same, latest date higher 
       Username, 
       Score 
     FROM TopScores) 
SELECT TOP 5 Pos, 
      Username, 
      Score 
FROM Rankings 
UNION ALL 
SELECT Pos, 
     Username, 
     Score 
FROM Rankings 
WHERE Pos BETWEEN (SELECT Pos 
        FROM Rankings 
        WHERE Username = @User) - 1 AND (SELECT Pos 
                 FROM Rankings 
                 WHERE Username = @User) + 1 

Мне пришлось индексировать таблицу, поэтому я добавил кластеризацию: сначала ci_TopScores (имя пользователя) и некластеризованное: nci_TopScores (Dateadded, Score).

В плане запроса было показано, что кластеризация была полностью проигнорирована (до того, как я создал некластеризованное тестирование и был использован в запросе), а логические чтения были больше (по сравнению со сканированием таблицы без какого-либо индекса).

Сортировка была самой дорогостоящей операцией. Таким образом, я скорректировал индексы для кластеризации: ci_TopScores (Score desc, Dateadded desc) и некластеризованный: nci_TopScores (Username).

Все еще стоит того же. Nonclustered: nci_TopScores (Имя пользователя) полностью игнорируется.

Как я могу избежать высокой стоимости сортировки и индексации этой таблицы эффективно?

+2

Замечание: использование 'char (255)' очень неэффективно - оно будет ** всегда ** использовать 255 байт - независимо от того, сколько символов вы храните, даже 'NULL' использует 255 символов! Любая строка длиной более 3-5 символов должна храниться как 'Varchar (n)' –

+0

Спасибо. Я сообщу людям таблицы. – Knightwisp

ответ

0

CTE не использует Username, поэтому не удивительно, что он не использует этот индекс.

CTE - это просто синтаксис. Вы оцениваете это CTE 4 раза.

Попробуйте #temp, поэтому его оценивают только один раз.
Но вам нужно подумать об индексах.
Я бы пропустить RowNumber и просто положить иден рк на #temp служить поз
я бы пропустить какие-либо другие индексы #temp

Для TopScores индекс по Score по алфавиту, DateAdded по алфавиту, Логин возрастанию воли помочь
Но это не поможет, если она раздроблена
то есть индекс, который будет фрагментировать при вставке

insert into #temp (Score, DateAdded, Username) 
select Score, DateAdded, Username 
from TopScores 
order by Score desc, DateAdded desc, Username asc 

select top 5 * 
    from #temp 
order by pos 
union 
select three.* 
from #temp 
join #temp as three 
    on #temp.UserName = @user 
and abs(three.pos - #temp.pos) <= 1 

Так что, если есть таблица проверки по #temp UserName.
Одно сканирование не займет столько времени, как создать один индекс.
Этот индекс был бы сильно фрагментирован.

+0

Большое спасибо. – Knightwisp

Смежные вопросы