Запросы к SQL Server: повышение производительности за счет сокращения предложений WHERE - PullRequest
0 голосов
/ 29 мая 2018

У меня есть запрос SQL от моего товарища по команде, который, как мне кажется, имеет много предикатов, и это является причиной плохой производительности.Выглядит это так:

WHERE 
      (@IdSenales IS NULL OR senalesIds.id = comp.IdSenal) 
      AND
      (@IdAnunciantes IS NULL OR anunciantesIds.id = comp.IdAnunciante) 
      AND                                    
      (@IdProgramas IS NULL OR programasIds.id = emision.IdProgramaVariante) 
      AND   
      (@IdTipoPublicidades IS NULL OR publicidadesIds.id = orden.IdTipoPublicidad) 
      AND
      (@Canje = 0 OR (@canje = 1 AND comp.IdTipoCondicionCobro !=  12)) 
      AND 
      (emision.Fecha BETWEEN @FechaDesdeContrato AND ISNULL(@FechaHastaContrato, emision.fecha)) 
      AND
      (comp.FechaEmision BETWEEN @FechaDesde AND @FechaHasta) 
      AND                                                   
      (@IdSectorImputacion = 0 OR @IdSectorImputacion = simp.IdSectorImputacion) 

Я из Аргентины, поэтому я комментирую по-испански (извините).

Мои вопросы: способ улучшить производительность, изменив сравнения?в предложении WHERE с созданной мной функцией, которая возвращает то же самое?

Большое спасибо,

Дэвид

Ответы [ 3 ]

0 голосов
/ 29 мая 2018

Как упоминает @ GordonLinoff , ваш лучший вариант - изучить используемые индексы.Он также намного лучше, чем я;так что прими его совет над моим, если сможешь.Однако, если по какой-то причине в вашей компании не разрешен динамический SQL или перезапись не возможна, читайте дальше ...

Возможно, у вас не такая большая проблема, как вы думаете;видели ли вы проблему с производительностью, или вы просто смотрите на код и думаете, что «много вещей происходит с большим количеством скобок, так что это плохо»?

то есть, взять эту строку: (@IdSenales IS NULL OR senalesIds.id = comp.IdSenal),При этом параметр сравнивается с нулевым значением, поэтому его нужно оценивать только один раз, а не один раз на строку;что не так уж плохо.После этого ничем не отличается от того, что у вас нет этого утверждения или только senalesIds.id = comp.IdSenal.То же самое верно для большинства этих строк.

Тем не менее, SQL сгенерирует план запроса при первом запуске этого кода и впоследствии будет использовать его для всех последующих запросов, независимо от того, какие параметры были использованы;поэтому план может быть совершенно неуместным для нового набора опций.Хорошим решением здесь является добавление OPTION (RECOMPILE).Вы найдете хорошее объяснение этому здесь: https://blogs.msdn.microsoft.com/robinlester/2016/08/10/improving-query-performance-with-option-recompile-constant-folding-and-avoiding-parameter-sniffing-issues/

Помимо этого, эта строка может быть проблемой, так как она включает применение функции, выход которой будет различным для каждой строки;так что будет нелегко оптимизировать:

  (emision.Fecha BETWEEN @FechaDesdeContrato AND ISNULL(@FechaHastaContrato, emision.fecha)) 

Измените это на:

  (emision.Fecha >= @FechaDesdeContrato AND (emision.Fecha <= @FechaHastaContrato )) 

... и вы должны быть в порядке.

Полный код:

WHERE 
    (@IdSenales IS NULL OR senalesIds.id = comp.IdSenal) 
    AND
    (@IdAnunciantes IS NULL OR anunciantesIds.id = comp.IdAnunciante) 
    AND                                    
    (@IdProgramas IS NULL OR programasIds.id = emision.IdProgramaVariante) 
    AND   
    (@IdTipoPublicidades IS NULL OR publicidadesIds.id = orden.IdTipoPublicidad) 
    AND
    (@Canje = 0 OR (@canje = 1 AND comp.IdTipoCondicionCobro !=  12)) 
    AND 
    (emision.Fecha >= @FechaDesdeContrato AND (@FechaHastaContrato is null or emision.Fecha <= @FechaHastaContrato )) 
    AND
    (comp.FechaEmision BETWEEN @FechaDesde AND @FechaHasta) 
    AND                                                   
    (@IdSectorImputacion = 0 OR @IdSectorImputacion = simp.IdSectorImputacion) 
OPTION (RECOMPILE)
0 голосов
/ 29 мая 2018

Спасибо за ваше предложение @JohnLBevan !!Я проверил предикаты, потому что я прочитал статью от Гейл Шоу, в которой говорилось:

"Еще одна распространенная причина выбора SQL Server для сканирования - это запрос, содержащий несколько предикатов, когда не существует ни одного индекса, содержащего все столбцы.необходимо оценить предложение WHERE. Например, индекс (FirstName, Surname) полностью поддерживал бы любой запрос с предложением WHERE FirstName = @FirstName AND Surname = @Surname. Однако, если был только один индекс только для FirstName,и второй отдельный индекс по фамилии, тогда SQL Server не может эффективно использовать ни один из них. Он может выбрать поиск одного индекса, выполнить поиск для других столбцов и затем выполнить вторичный фильтр, он может выбрать поиск обоих индексов и выполнить пересечение индексаили он может сдаться и отсканировать таблицу. "

https://www.red -gate.com / simple-talk / sql / администрация базы данных / gail-shaws-sql-server-howlers /

Когда я прочитал это, я вспомнил, что видел несколько предикатов в своем запросе.Я хочу упомянуть, что этот запрос является одним из самых дорогих запросов, который возвращает мой запрос, чтобы проверить стоимость всех запросов к базе данных.Что ж, я должен проверить, достаточно ли индексов и / или создать новые.

Дэвид Линарес.

0 голосов
/ 29 мая 2018

Это немного длинно для комментария.

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

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

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

...