Удивительное увеличение скорости SQL - PullRequest
13 голосов
/ 19 декабря 2008

Я только что обнаружил, что производительность плана выполнения между следующими двумя операторами выбора сильно отличается:

select * from your_large_table
where LEFT(some_string_field, 4) = '2505'

select * from your_large_table
where some_string_field like '2505%'

Планы выполнения составляют 98% и 2% соответственно. Немного разницы в скорости. Я был шокирован, когда увидел это.

Я всегда делал LEFT (xxx) = 'yyy', так как он хорошо читается. Я на самом деле узнал об этом, проверив сгенерированный LINQ SQL и мой вручную созданный SQL. Я предполагал, что команда LIKE будет медленнее, но на самом деле намного быстрее.

У меня вопрос, почему LEFT () медленнее, чем LIKE "% ..". Они в конце концов идентичны?

Кроме того, есть ли сбой процессора при использовании LEFT ()?

Ответы [ 7 ]

23 голосов
/ 19 декабря 2008

Говоря в общем, вы никогда не должны использовать функцию в левой части предложения WHERE в запросе. Если вы это сделаете, SQL не будет использовать индекс - он должен оценивать функцию для каждой строки таблицы. Цель состоит в том, чтобы убедиться, что ваше предложение where равно « Sargable »

Некоторые другие примеры:

Bad: Select ... WHERE isNull(FullName,'') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 

Bad: Select ... WHERE Year(OrderDate) = 2003
Fixed: Select ... WHERE OrderDate >= '2003-1-1' AND OrderDate < '2004-1-1'
17 голосов
/ 19 декабря 2008

Похоже, выражение LEFT (some_string_field, 4) вычисляется для каждой строки полного сканирования таблицы, в то время как выражение «like» будет использовать индекс.

Оптимизация «нравится» для использования индекса, если это шаблон с передней привязкой, - это намного более простая оптимизация, чем анализ произвольных выражений с использованием строковых функций.

7 голосов
/ 19 декабря 2008

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

3 голосов
/ 19 декабря 2008

Если вы используете функцию для столбца с индексом, то база данных больше не использует индекс (по крайней мере, с Oracle в любом случае)
Поэтому я предполагаю, что в вашем примере поля 'some_string_field' есть индекс, который не используется для запроса с 'LEFT'

1 голос
/ 25 февраля 2015

Как уже упоминалось @BradC, вы не должны использовать функции в предложении WHERE, если у вас есть индексы и вы хотите ими воспользоваться.

Если вы читаете раздел «Использовать LIKE вместо LEFT () или SUBSTRING () в предложениях WHERE при наличии индексов» из этих Советов по производительности SQL , есть и другие примеры.

Здесь также намекают на вопросы, с которыми вы столкнетесь на экзаменах MCSE SQL Server 2012 , если вы тоже заинтересованы в них. : -)

1 голос
/ 19 декабря 2008

Здесь произошло либо то, что СУБД не может использовать индекс для предиката LEFT () и может использовать его в LIKE, либо она просто сделала неправильный вызов, в котором был бы более подходящий метод доступа .

Во-первых, для некоторых РСУБД может быть справедливо, что применение функции к столбцу не позволяет использовать метод доступа на основе индекса, но это не универсальная истина, и при этом нет логической причины, почему это необходимо. Метод доступа на основе индекса (такой как полное сканирование индекса Oracle или быстрое полное сканирование индекса) может быть полезным, но в некоторых случаях СУБД не может работать в контексте предиката на основе функции.

Во-вторых, оптимизатор может просто неправильно понять арифметику при оценке преимуществ различных доступных методов доступа. Предполагая, что система может выполнить метод доступа на основе индекса, она сначала должна сделать оценку числа строк, которые будут соответствовать предикату, либо из статистики в таблице, статистики по столбцу, путем выборки данных во время анализа, или использовать эвристическое правило (например, «предположим, 5% строк будут совпадать»). Затем он должен оценить относительную стоимость полного сканирования таблицы или доступных методов на основе индекса. Иногда это может привести к неправильной арифметике, иногда статистика будет вводить в заблуждение или неточна, а иногда эвристические правила не будут подходить для набора данных.

Ключевым моментом является знание ряда проблем:

  1. Какие операции может поддерживать ваша СУБД?
  2. Что будет наиболее подходящей операцией в Если вы работаете с?
  3. Правильный ли выбор системы?
  4. Что можно сделать, чтобы позволить системе выполнять более эффективную операцию (например, добавить отсутствующее ненулевое ограничение, обновить статистику и т. Д.)?

По моему опыту, это не тривиальная задача, и часто ее лучше оставлять экспертам. Или, с другой стороны, просто опубликуйте проблему в Stackoverflow - некоторые из нас находят это увлекательным, собака помогает нам.

1 голос
/ 19 декабря 2008

Почему вы говорите, что они идентичны? Они могут решить одну и ту же проблему, но у них другой подход. По крайней мере, так кажется ...

Запрос, использующий LEFT, оптимизирует тест, так как он уже знает о длине префикса и т. Д., Поэтому в программе на C / C ++ / ... или без индекса - алгоритм, использующий LEFT для реализации определенного LIKE. поведение будет самым быстрым. Но в отличие от большинства не декларативных языков, в базе данных SQL вам предстоит сделать много оптимизаций. Например, LIKE, вероятно, реализуется сначала путем поиска знака%, и если замечено, что% является последним символом в строке, запрос можно оптимизировать во многом так же, как вы делали с помощью LEFT, но непосредственно с использованием индекса .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...