Как обходной путь в SQL (проблемы с производительностью) - PullRequest
6 голосов
/ 11 сентября 2010

Я читал и обнаружил, что использование LIKE приводит к значительному замедлению запросов.

Рабочий рекомендовал использовать

Select Name
From mytable
a.Name IN (SELECT Name 
           FROM mytable
           WHERE Name LIKE '%' + ISNULL(@Name, N'') + '%' 
           GROUP BY Name)

вместо

Select Name
From mytable
a.Name LIKE '%' + ISNULL(@Name, N'') + '%'

Теперь я не эксперт по SQL и не очень понимаю внутреннюю работу этих операторов. Стоит ли этот вариант лучше набрать несколько дополнительных символов с каждым оператором like? Есть ли еще лучшая (и легче набираемая) альтернатива?

Ответы [ 3 ]

9 голосов
/ 11 сентября 2010

Необходимо решить несколько проблем с производительностью ...

Не обращаться к одной и той же таблице более одного раза, если это возможно

Не использовать подзапрос для критериев, которые могутбыть сделано без необходимости ссылки на дополнительные копии той же таблицы.Это приемлемо, если вам нужны данные из копии таблицы из-за использования агрегатных функций (MAX, MIN и т. Д.), Хотя аналитические функции (ROW_NUMBER, RANK и т. Д.) Могут быть более удобными (при условии поддержки).

Не сравнивайте то, что вам не нужно

Если ваш параметр имеет значение NULL, а это означает, что вы хотите получить любое значение для сравниваемых столбцов, не включайте критерии фильтрации.Такие выражения:

WHERE a.Name LIKE '%' + ISNULL(@Name, N'') + '%'

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

Более эффективный подход будет следующим:

IF @Name IS NOT NULL 
BEGIN
   SELECT ...
     FROM ...
    WHERE a.name LIKE '%' + @Name + '%'
END
ELSE 
BEGIN
   SELECT ...
     FROM ...
END

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

Использовать правильный инструмент

Оператор LIKE неочень эффективен при поиске текста, когда вы проверяете наличие строки в текстовых данных. Технология полнотекстового поиска (FTS) была разработана для устранения недостатков:

IF @Name IS NOT NULL
BEGIN
   SELECT ...
     FROM ...
    WHERE CONTAINS(a.name, @Name) 
END
ELSE
BEGIN
   SELECT ...
     FROM ...
END

Всегда проверяйте и сравнивайте

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

8 голосов
/ 11 сентября 2010

Просто сравните планы выполнения, и вы увидите разницу.

У меня нет ваших точных данных, но я выполнил следующие запросы к моей базе данных SQL Server 2005 (да, это зануда):

SELECT     UnitName
FROM         Units
WHERE     (UnitName LIKE '%Space Marine%')

SELECT     UnitName
FROM         Units
WHERE     UnitName IN (
   (SELECT UnitName FROM Units 
   WHERE UnitName LIKE '%Space Marine%' GROUP BY UnitName)
)

Вот мои результаты выполнения плана:

alt text

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

4 голосов
/ 11 сентября 2010

Если IIQR не является какой-то меньшей таблицей, которая каким-то образом индексирует имена (и не является исходной таблицей, запрашиваемой здесь с самого начала), я не вижу, как эта более длинная версия помогает вообще; он делает то же самое, но просто добавляет дополнительный шаг создания набора результатов, который используется при IN.

Но я был бы сомнителен, даже если бы IIQR была меньшей «индексной» таблицей. Мне бы хотелось узнать больше о рассматриваемой базе данных и о том, какой план запроса будет для каждой.

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

В зависимости от размера рассматриваемой таблицы; это может вообще не иметь значения.

Для вы , хотя; Я бы посоветовал, чтобы это было проще. Если вы на самом деле не знаете, какое влияние окажет усложнение запроса на производительность, может быть трудно решить, каким образом это делать.

...