2016-02-25 8 views
1

Нижеприведенный запрос обращается к таблице голосов, содержащей более 30 миллионов строк. Затем набор результатов выбирается из WHERE n = 1. В плане запроса операция SORT в оконной функции ROW_NUMBER() составляет 95% от стоимости запроса, и для завершения выполнения требуется более 6 минут.ROW_NUMBER() Query Plan SORT Optimization

У меня уже есть индекс на same_voter, eid, country include vid, nid, sid, vote, time_stamp, new, чтобы покрыть предложение where.

Самый эффективный способ исправить это, чтобы добавить индекс на vid, nid, sid, new DESC, time_stamp DESC или есть ли альтернатива использованию функции ROW_NUMBER() для достижения таких же результатов более эффективным образом?

SELECT v.vid, v.nid, v.sid, v.vote, v.time_stamp, v.new, v.eid, 
    ROW_NUMBER() OVER (
     PARTITION BY v.vid, v.nid, v.sid ORDER BY v.new DESC, v.time_stamp DESC) AS n 
FROM dbo.Votes v 
WHERE v.same_voter <> 1 
    AND v.eid <= @EId 
    AND v.eid > (@EId - 5) 
    AND v.country = @Country 
+0

95% для операции не так важно, вам нужно посмотреть на весь запрос. Это очень медленно? Единственное, что я вижу, это проблемы с параметрами нюхания, так как у вас есть 2 параметра. Индекс: fine.https://www.brentozar.com/archive/2013/06/the-elephant-and-the-mouse-or-parameter-sniffing-in-sql-server/ – Mihai

+0

Я заявил в вопросе, что он занимает 6 минут. Кроме того, индекс, который вы называете хорошим, не связан с вопросом/вопросом, поскольку ROW_NUMBER() SORT является настолько дорогостоящим. – Namrehs

+0

Индекс плохой, так как он начинается с 'same_voter', который фильтруется' <> 1' (если большинство значений не равно «1», и ваш индекс фильтруется). Я бы рекомендовал изменить начальный столбец индекса на наиболее избирательный в вашем случае. Создание полной таблицы чисел (ROW_NUMBER) для фактического принятия первого/последнего ONE_ не является лучшей идеей. Вы не имеете никаких шансов использовать sql-сервер для использования любого индекса и просто выберите min/max/top1. Ваша задача сервера - перечислить все строки, а затем ... _ok, я возьму сначала one_. –

ответ

1

Одна из возможных альтернатив использованию ROW_NUMBER():

SELECT 
    V.vid, 
    V.nid, 
    V.sid, 
    V.vote, 
    V.time_stamp, 
    V.new, 
    V.eid 
FROM 
    dbo.Votes V 
LEFT OUTER JOIN dbo.Votes V2 ON 
    V2.vid = V.vid AND 
    V2.nid = V.nid AND 
    V2.sid = V.sid AND 
    V2.same_voter <> 1 AND 
    V2.eid <= @EId AND 
    V2.eid > (@EId - 5) AND 
    V2.country = @Country AND 
    (V2.new > V.new OR (V2.new = V.new AND V2.time_stamp > V.time_stamp)) 
WHERE 
    V.same_voter <> 1 AND 
    V.eid <= @EId AND 
    V.eid > (@EId - 5) AND 
    V.country = @Country AND 
    V2.vid IS NULL 

Запрос в основном говорит, чтобы получить все строки по вашим критериям, а затем присоединиться к другим строкам, которые соответствуют тем же критериям, но которые будут ранжироваться выше для раздела на основе столбцов new и time_stamp. Если ни один не найден, то это должна быть строка, которую вы хотите (она занимает наибольшее место), и если ни один не найден, это означает, что V2.vid будет NULL. Я предполагаю, что vid иначе никогда не может быть NULL. Если это столбец NULL в вашей таблице, вам необходимо настроить последнюю строку запроса.

+0

Спасибо, я проверю это. Вы правы, 'vid' не имеет значения NULL. – Namrehs

+0

В итоге я сделал что-то очень похожее на это. Еще раз спасибо. – Namrehs

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

  • Нет связанных вопросов^_^