Ограничить количество строк, обрабатываемых в этом запросе - PullRequest
0 голосов
/ 10 декабря 2011

Я не могу опубликовать фактический запрос здесь, поэтому я публикую основной план запроса, которого должно быть достаточно. Запрос используется для просмотра страницы и получения набора пользователей, ранжированных в соответствии с выводом функции, например, F. F берет параметры из таблицы User и других таблиц, которые объединяются. Запрос выглядит примерно так:

Select TOP (20) 
from (select row_number OVER (Order By F desc) as rownum, 
             user.*, .. 
      from user 
      inner join X on user.blah = X.blah 
      left outer join Y on user.foo = Y.foo 
      where DATEDIFF(dd, LastLogin, GetDate()) > 200 and Y.bar > FUBAR) as temp 
where rownum > 0  

Согласно плану выполнения, 91% стоимости приходится на сортировку. Поскольку сортировка основана на F, я не могу добавить индекс для ускорения сортировки. Внутренний запрос запрашивает все записи, фильтрует и сортирует. Теперь большую часть времени пользователи просто смотрят на результаты на 1 - 5 страницах (1 страница имеет 20 записей, следовательно, Top (20)), поэтому я подумал, есть ли способ ограничить количество обрабатываемых и отсортированных строк и сделать запрос выполняется быстрее и требует меньше ресурсов процессора.

РЕДАКТИРОВАТЬ: Когда я говорю, чтобы вычислить F таблицы объединяются, я имею в виду это. F принимает такие параметры, как X.blah и Y.foo и Y.bar. Вот и все. Все эти параметры также должны быть возвращены как часть набора результатов. например Широта и долгота последнего местоположения пользователя хранятся в X.

Ответы [ 3 ]

3 голосов
/ 10 декабря 2011

По крайней мере, вы можете попытаться не вызывать DATEDIFF в каждой строке

declare @target_date datetime
set @target_date = DATEADD(dd, -200, GetDate())

Select TOP (20) 
from (select row_number OVER (Order By F desc) as rownum, 
             user.*, .. 
      from user 
      inner join X on user.blah = X.blah 
      left outer join Y on user.foo = Y.foo 
      where LastLogin < @target_date and Y.bar > FUBAR) as temp 
where rownum > 0  

Возможно, сделать то же самое с FUBAR и F?

Приведенный выше пример не дает вам большой производительности, но дает общее представление о том, как уменьшить количество вызовов функций

1 голос
/ 11 декабря 2011

Некоторые мысли:

  1. Какая функция F?Можно ли его переписать как встроенную табличную функцию?Это дало бы оптимизатору возможность расширить функцию в повторно используемый план выполнения.

  2. Вы выполняете LEFT OUTER JOIN на Y, но затем включаете столбец с Y в свой WHEREпредложение, эффективно отображающее его как ВНУТРЕННЕЕ СОЕДИНЕНИЕ.Хотя оптимизатор, вероятно, отображает план выполнения таким же образом, я бы исправил это, чтобы в будущем было проще устранить неполадки.

1 голос
/ 11 декабря 2011

Не уверен, если и насколько это поможет - но две вещи:

  1. Можете ли вы убедиться, что все столбцы и столбцы внешнего ключа в предложении WHERE (user.blah, X.blah, user.foo, Y.foo, Y.bar) действительно проиндексированы? Это значительно повысит производительность JOIN.

    Если эти столбцы не проиндексированы, в плане выполнения также может быть операция сортировки, которую использует SQL Server, чтобы он мог затем использовать соединение слиянием для данных. Таким образом, ваш вид может даже не исходить из OVER (ORDER BY F DESC), который, по вашему мнению, вызывает сортировку

  2. вы комбинируете TOP (20) с номерами строк, но вы не определяете какие-либо действительные ORDER BY для полного набора результатов - так что ваши результаты будут в лучшем случае случайными. Кроме того, если вы уже определили rownum, не могли бы вы просто использовать:

    SELECT (columns)
    FROM (.......) as temp 
    WHERE rownum BETWEEN 0 AND 20 
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...