Удивительное увеличение скорости SQL
Только что выяснилось, что производительность плана выполнения между следующими двумя операциями select значительно отличается:
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()?
Ответы
Ответ 1
В более общем плане вы никогда не должны использовать функцию на стороне LEFT предложения 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'
Ответ 2
Похоже, что выражение LEFT (some_string_field, 4) оценивается для каждой строки полного сканирования таблицы, в то время как выражение "как" будет использовать индекс.
Оптимизация "как" для использования индекса, если он является привязанным к фронту шаблоном, намного проще, чем анализ произвольных выражений с использованием строковых функций.
Ответ 3
Огромное влияние на использование вызовов функций в тех случаях, когда SQL Server должен вычислять результат для каждой строки. С другой стороны, like
- это встроенная функция языка, которая сильно оптимизирована.
Ответ 4
Если вы используете функцию в столбце с индексом, тогда db больше не использует индекс (по крайней мере, с Oracle в любом случае)
Поэтому я предполагаю, что поле вашего примера "some_string_field
" имеет индекс, который не используется для запроса с "LEFT"
Ответ 5
Почему вы говорите, что они идентичны? Они могут решить ту же проблему, но их подход отличается. По крайней мере, это похоже на то, что...
Запрос с использованием LEFT оптимизирует тест, поскольку он уже знает о длине префикса и т.д., поэтому в программе C/С++/... или без индекса алгоритм, использующий LEFT для реализации определенного LIKE поведение будет самым быстрым. Но в отличие от большинства не декларативных языков, в базе данных SQL для вас выполняется много оптимизаций op. Например, LIKE, вероятно, реализуется, сначала ищет знак%, и если будет замечено, что% является последним char в строке, запрос можно оптимизировать так же, как и с LEFT, но напрямую используя индекс.
Итак, действительно, я думаю, что вы были правы в конце концов, они, вероятно, одинаковы в своем подходе. Единственное различие заключается в том, что сервер db может использовать индекс в запросе с использованием LIKE, потому что нет функции, преобразующей значение столбца в нечто неизвестное в предложении WHERE.
Ответ 6
Здесь произошло либо то, что RDBMS не может использовать индекс в предикате LEFT() и может использовать его в LIKE, либо просто ошибочный вызов, в котором будет более подходящий метод доступа.
Во-первых, для некоторых РСУБД может быть справедливо, что применение функции к столбцу предотвращает использование метода доступа на основе индексов, но это не универсальная истина, и нет никакой логической причины, почему это должно быть. Метод доступа на основе индексов (например, полное сканирование индексов или быстрое полное сканирование индекса) может быть полезным, но в некоторых случаях РСУБД не может работать в контексте предиката, основанного на функции.
Во-вторых, оптимизатор может просто получить арифметику неправильно при оценке преимуществ различных доступных методов доступа. Предполагая, что система может выполнять метод доступа на основе индексов, она должна сначала оценить количество строк, которые будут соответствовать предикату, либо из статистики в таблице, статистики по столбцу, путем выборки данных во время разбора, или использовать эвристическое правило (например, "предположим, что 5% строк будут соответствовать" ). Затем он должен оценить относительные затраты на полное сканирование таблицы или доступные методы на основе индексов. Иногда это приведет к неправильной арифметике, иногда статистика будет вводить в заблуждение или неточно, а иногда эвристические правила не подходят для набора данных.
Ключевым моментом является осознание ряда проблем:
- Какие операции могут поддерживать ваши РСУБД?
- Что было бы наиболее подходящей операцией в
с которым вы работаете?
- Правильно ли выбран правильный выбор системы?
- Что можно сделать, чтобы позволить системе выполнять более эффективную операцию (например, добавить отсутствующее не нулевое ограничение, обновить статистику и т.д.)?
По моему опыту, это не тривиальная задача, и ее часто лучше всего оставлять экспертам. Или, с другой стороны, просто отправьте проблему Stackoverflow - некоторые из нас находят этот материал увлекательным, собака помогает нам.
Ответ 7
Как упоминалось в @BradC, вы не должны использовать функции в предложении WHERE, если у вас есть индексы и вы хотите их использовать.
Если вы читаете раздел "Использовать LIKE вместо LEFT() или SUBSTRING() в предложениях WHERE при наличии индексов" из этих советов по производительности SQL, есть еще примеры.
Он также намекает на вопросы, которые вы встретите на экзаменах MCSE SQL Server 2012, если вы тоже хотите их принять.: -)