3

У нас есть широкая таблица, которую мы в настоящее время пытаемся оптимизировать. Таблица имеет 50 столбцов (статистика), которые мы в конечном итоге хотим ранжировать в порядке убывания. В настоящее время насчитывается более 5 миллионов строк.Оптимизация индексов для ранжирования в SQL Server

Мы ищем способы оптимизации этой таблицы как с точки зрения сокращения сложности, так и для повышения скорости чтения. Скорость записи также важна для нас, но чтение более критично. Ранжирование этих статистических данных должно быть максимально приближенным к реальному времени, при этом оптимальным решением является тот, который быстро устанавливается на основе запроса (новые строки все время добавляются, и мы хотим как можно скорее показать ранги для этих строк .)

В настоящее время мы оцениваем, будет ли вертикальная таблица компоновкой.) Более результативной и b) легче работать.

Поскольку статистика, что в настоящее время, вставленная не обязательно четко определена, это легче для нас, если они не жестко закодированы в таблицу (отсюда предпочтение вертикальной структуры таблицы.)

Вот взгляд на наша текущая структура таблицы и запрос:

CREATE TABLE Stats 
(
    Id BIGINT PRIMARY KEY NOT NULL, 
    UserId INT, 
    Name VARCHAR(32) NOT NULL, 
    Value DECIMAL(10,4) DEFAULT ((0)) NOT NULL, 
    UpdatedAt DATETIME 
); 

CREATE INDEX Leaderboard__index ON Stats (Name, Value DESC); 

SELECT 
    Id, 
    Name, 
    Value, 
    RANK() OVER (PARTITION BY Name ORDER BY Value DESC) AS Rank 
FROM 
    Stats 
ORDER BY 
    Value DESC 

Обычно мы бы либо искать для верхних N строк для любого данного стата (как лидеры), или мы будем выбирать один UserId и получить ранг всех статистика, связанная с этим UserId.

Данные значительных размеров (как я уже упоминал выше, потому что есть много строк и много колонн, вертикальная структура таблицы может находиться в диапазоне от 250 миллионов строк, и будет продолжать расти.)

Мы стремимся получать эти данные как можно быстрее, независимо от того, какое оборудование требуется, секунды - наша цель, так как мы сейчас находимся в диапазоне минут.

В испытании вертикальной структуры таблицы мы вставленная более 400 000 строк данных и запрос выше, занимает немного меньше чем за 3 минуты (хотя это также потребовалось всего около 18 секунд меньше, чтобы ранжировать 10000 строк.)

Я хотел бы услышать любые предложения. Спасибо за ваше время!

+1

Вы можете обновить свои тэги с версией SQL Server, а также указать, какое издание вы используете (стандартное, корпоративное и т. Д.)? Ta. –

+0

Исходя из вышесказанного, я бы рекомендовал создать другую таблицу, которая поддерживала бы, скажем, 100-го списка пользователей рейтинга с наименьшим количеством баллов. Это значительно уменьшит размер данных, но не позволит ранжировать пользователей за пределами топ-100. – Alex

+0

@Alex. Извлечение лучших 10 000 строк занимает всего пару сотен миллисекунд в оба конца с сервера. Дизайн верхней таблицы N для нас проблематичен, потому что - основанный на нашем дизайне пользовательского интерфейса - тривиально перейти от просмотра 100 лучших к просмотру 100 строк со смещением 100 000. – lwansbrough

ответ

7

индекс у вас есть не полезен для вашей оконной функции, потому что

1.To получить ID значения столбца, SQL может в конечном итоге делает ключевую Lookups или даже в конечном итоге сканирования всего другой индекс, если он пересекает Tipping point. Ваш индекс не может быть использован вообще.

2.You заказывает по валям алфавита, который требует своего рода без какого-либо подходящего индекса и может даже endup spilling to TEMPDB

3.Для еще одной интересной fragmenation аспекта см ниже

Обычно для функции окна, чтобы выполнить хорошо, вы будете нуждаться в POC индексе, который означает

P, O - Partition и порядок по столбцам должно быть в ключевом пункте
C - покрытие --columns вы в том числе в выберите должны быть включены

Так ниже запроса для оптимальной работы.

SELECT 
    Id, 
    Name, 
    Value, 
    RANK() OVER (PARTITION BY Name ORDER BY Value DESC) AS Rank 
FROM 
    Stats 
ORDER BY 
    Value DESC 

Вам нужно будет ниже индекса

create index nci_test on dbo.table(name,value desc) 
include(id) 

Существует еще одна проблема с индексом создается с "value desc".

Обычно в индексе все значения будут сохраняться в порядке возрастания по умолчанию, но с этим индексом вы запрашиваете сохранение в обратном порядке, что может привести к логической фрагментации, которая может быть видна с answer из Martin Smith здесь. термины из ответа здесь ...

Если индекс создан с уменьшающимися ключами, но новые строки добавляются с возрастающими значениями ключа, то вы можете завершить каждую страницу из логического порядка. Это может серьезно повлиять на размер IO читает при сканировании таблицы и не в кэше

Так несколько вариантов ..

1.Run индекс перестроение основанный на вашей частоте, чтобы увидеть, если это помогает

2.Changing запрос на заказ пунктом раздела устранит необходимость индекс должен быть создан с «валь DESC» вариант

SELECT 
     Id, 
     Name, 
     Value, 
     RANK() OVER (PARTITION BY Name ORDER BY Value DESC) AS Rank 
    FROM 
     Stats 
    ORDER BY 
     name DESC 

выше оленья кожа запрос нужен индекс, который будет создан л икэ тот, который вы создали .Вы можете изменить его, как below..which также заботится о фрагментации аспектов отмечено выше

CREATE INDEX Leaderboard__index ON Stats (Name, Value) 
include(id); 

Ссылки:
Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions

+0

Ничего себе, спасибо за этот невероятно продуманный ответ. Я сейчас попробую. – lwansbrough

+0

Ты волшебник. '400000 строк, полученных начиная с 1 в 17s 386ms (исполнение: 238ms, выборка: 17s 148ms)' – lwansbrough

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