Что делает оператор SQL саргным?

253

По определению (по крайней мере из того, что я видел) sargable означает, что запрос способен заставить механизм запросов оптимизировать план выполнения, который использует запрос. Я пытался найти ответы, но, кажется, не так много по теме. Итак, вопрос в том, что делает или не делает SQL-запрос саргным? Любая документация будет принята с благодарностью.

Для справки: SARGable

DForck42
источник
58
+1 за "sargable". Это мое слово на сегодня. :-p
BFree
1
Я мог бы также добавить к ответу Адама, что горы информации в большинстве случаев чрезвычайно специфичны для каждого механизма БД.
Hoagie
31
SARG = Поиск ARGument. Забавно то, что «SARG» по-немецки означает «Гроб», поэтому мне всегда приходится улыбаться, когда люди говорят о SARGABLE - его можно положить в гроб? :-)
marc_s
гибкость зависит от вашей среды. MySQL документирован здесь: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Фрэнк Фармер,
Наличие свободных текстовых полей вместо «справочных таблиц» также противоречит духу создания запроса. При вводе произвольного текста (например, название города) пользователи ошибаются, в то время как справочные таблицы вынуждают пользователей выбирать правильно написанную запись. Стоит немного дополнительных проблем, потому что это можно правильно проиндексировать вместо использования LIKE "% ...%" в предикате.
Обратный инженер

Ответы:

256

Самая распространенная вещь, которая делает запрос несортируемым - это включение поля внутри функции в предложении where:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

Оптимизатор SQL не может использовать индекс myDate, даже если он существует. Буквально придется оценивать эту функцию для каждой строки таблицы. Намного лучше использовать:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

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

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = '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()) 
BradC
источник
7
Приведет ли включение функции внутрь GROUP BYзапроса к тому, что запрос станет несортируемым?
Майк Бэйли
1
Некоторые движки баз данных (Oracle, PostgreSQL) поддерживают индексы выражений, не знаете?
Крейг
3
Будет еще лучше вариант WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))быть SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Мне однажды сказал парень по оптимизации, что использование OR в предложении where может отменить запросы ...?
High Plains Grifter
2
@HighPlainsGrifter вы должны использовать UNION ALL в этом запросе - union имеет неявное отличительное значение, что делает запрос намного более дорогим, чем это необходимо, когда вам приходится использовать взаимоисключающие наборы данных
Devin Lamothe
1
@BradC В MSSQL 2016 нет разницы в плане выполнения между Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'и Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Они оба используют индекс FullName и выполняют поиск по индексу.
CEGRD
79

Не делай этого:

WHERE Field LIKE '%blah%'

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

Не делай этого:

WHERE FUNCTION(Field) = 'BLAH'

Это вызывает сканирование таблицы / индекса.

Сервер базы данных должен будет сравнить FUNCTION () с каждой строкой таблицы, а затем сравнить ее с BLAH.

Если возможно, сделайте это в обратном порядке:

WHERE Field = INVERSE_FUNCTION('BLAH')

Это запустит INVERSE_FUNCTION () для параметра один раз и все еще позволит использовать индекс.

пляж
источник
5
Ваше предложение с переворотом функции действительно сработает только тогда, когда функция выполняет обход данных (это означает, что f (f (n)) = n).
Адам Робинсон
5
Правда. Я подумал добавить INVERSE_FUNCTION, но не хотел сбивать с толку. Я изменю это.
пляж
9

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

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

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

Вы можете найти подробный пост и пример здесь .

Дрис ван Хансевейк
источник
4

Для того чтобы операция считалась пригодной для выполнения, недостаточно просто иметь возможность использовать существующий индекс. В приведенном выше примере добавление вызова функции к индексируемому столбцу в предложении where, скорее всего, по-прежнему использует некоторые преимущества определенного индекса. Он будет «сканировать», то есть извлекать все значения из этого столбца (индекса), а затем удалит те, которые не соответствуют предоставленному значению фильтра. Это все еще недостаточно эффективно для таблиц с большим количеством строк. Что действительно определяет sargability, так это возможность запроса обходить индекс b-дерева, используя метод двоичного поиска, который основывается на исключении половины набора для массива отсортированных элементов. В SQL это будет отображаться в плане выполнения как «поиск по индексу».

user2011845
источник