2014-01-15 3 views
0

У меня был обзор производительности SQL сделано по проекту, мы работаем, и один «критический» элемент, который придумал это:Wildcard Использование Pattern

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

SELECT * 
FROM TabFoo 
WHERE ColBar = @someparam OR @someparam IS NULL 

Их рекомендация:

Во многих случаях, OPTION (RECOMPILE) намек может быть быстрым обходным путем. С точки зрения дизайна вы также можете рассмотреть возможность использования отдельных опций Если или (не рекомендуется) использовать динамический оператор SQL.

Динамический SQL, безусловно, неверный путь вперед. В принципе, это процедура, в которой я ищу что-то, или что-то еще. В процедуру входят два параметра, и я фильтрую один или другой.

Лучший пример того, что они показали это:

SELECT .. 
FROM... 
WHERE (ColA = @ParA OR @ColA IS NULL) 
(AND ColB = @ParB OR @ParB IS NULL) 

Это плохая практика, и, кроме динамического SQL (потому что я думал, что динамический SQL не может реально составить и быть более эффективным в его плане выполнения?), как это было бы лучше всего сделано?

+0

Я не вижу, чтобы вы использовали подстановочные знаки вообще. –

+0

Единственный шаблон, который я вижу, находится в предложении select. Всегда полезно перечислить (и свести к минимуму) возвращаемые столбцы. О чем говорит ваш обзор? – Malk

+0

термин «подстановочный знак» вводит в заблуждение, он ссылается на используемую технику where where (которую я использовал несколько раз сам) – CodeMonkey1313

ответ

2

Запрос как

select * 
from foo 
where foo.bar = @p OR @p is null 

может или не может вызвать сканирование таблицы. Мой опыт в том, что он не будет: оптимизатор отлично умеет делать индексный поиск по выражению foo.bar = @p, предполагая подходящий индекс. Кроме того, он отлично способен закоротить объекты, если переменная равна нулю. Вы не будете знать, как выглядит ваш план выполнения, пока вы не попробуете его и не проверите связанную плоскость выполнения. Лучшей техникой является, однако, следующее:

select * 
from foo 
where foo.bar = coalesce(@p,foo.bar) 

, который даст вам такое же поведение.

Если вы используете хранимые процедуры, одна вещь, которая может и укусить вас в tookus что-то вроде этого:

create dbo.spFoo 

    @p varchar(32) 

as 

    select * 
    from dbo.foo 
    where foo.bar = @p or @p = null 

    return @@rowcount 

Прямое использование параметра хранимой процедуры в котором положение будет вызывать план кеширования должен быть основан на значении @p при его первом выполнении.Это означает, что если первое выполнение вашей хранимой процедуры имеет значение outlier для @p, вы можете получить план выполнения кэширования, который действительно работает для 95% «нормальных» исполнений и действительно хорош только для случаев с нечеткой ситуацией. Чтобы предотвратить это, вы хотите сделать это:

create dbo.spFoo 

    @p varchar(32) 

as 

    declare @pMine varchar(32) 
    set @pMine = @p 

    select * 
    from dbo.foo 
    where foo.bar = @pMine or @pMine = null 

    return @@rowcount 

Это простое задание параметра локальной переменной делает это выражение и поэтому кэшировать план выполнения не связан с начальным значением @p. Не спрашивайте, как я это знаю.

Далее рекомендация вы получили:

Во многих случаях, OPTION (RECOMPILE) намек может быть быстрым обходным путем. С точки зрения дизайна, вы также можете рассмотреть возможность использования отдельных аргументов If или (не рекомендуется) с помощью динамического оператора SQL.

- hogwash. Option(recompile) означает, что хранимая процедура перекомпилируется при каждом исполнении. Когда скомпилированная хранимая процедура компилируется, блокировка времени блокируется на зависимом объекте. Кроме того, никто другой не сможет выполнить хранимую процедуру до завершения компиляции. Это, скажем так, отрицательное влияние на параллелизм и производительность. Использование option(recompile) должно быть крайней мерой.

Пишите чистый SQL и проверяйте свои планы выполнения с использованием производственных данных или как можно ближе к нему: на ваш план выполнения влияет размер и форма/распределение данных.

1

Возможно, я ошибаюсь, но я уверен, что сканирование таблицы произойдет независимо от того, что если столбец, который у вас есть в вашем предложении where, не проиндексирован. Кроме того, вы могли бы получить лучшую производительность, переупорядочив свои предложения OR, чтобы, если @ParA IS NULL истинно, он сначала оценивает и не требует оценки значения в столбце. Следует помнить, что предложение where оценивается для каждой строки, которая возвращается из предложения from. Я бы не рекомендовал динамический SQL, и, честно говоря, даже при относительно большой нагрузке мне было бы трудно поверить, что эта форма фильтра приведет к значительным результатам производительности, поскольку сканирование таблицы требуется в любое время, когда столбец не индексируется.

+0

Стандарт SQL позволяет бесплатному правлению оптимизатора оценивать вещи в предложении where в любом порядке, который он так выбирает, при условии сохранения семантики дерева синтаксического анализа. 'где A = B или B имеет значение null ', семантически идентичен' where B является нулевым или A = B' и должен приводить к такому же плану выполнения. При этом в редких случаях я видел ситуации, когда переупорядочение частей [обычно очень сложного] предложения WHERE * приводило к различным планам исполнения. –

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