Що робить оператор SQL придатним для використання?


252

За визначенням (принаймні з того, що я бачив) sargable означає, що запит здатний, щоб система запитів оптимізувала план виконання, який використовується в запиті. Я спробував шукати відповіді, але, здається, не багато в цьому питанні. Отже, питання полягає в тому, що робить або не робить SQL-запит придатним для збору? Будь-яка документація буде дуже вдячна.

Для довідки: SARGable


58
+1 для "sargable". Це моє сьогоднішнє слово. :-p
BFree

1
Я можу також додати до відповіді Адама, що гори інформації в більшості випадків є надзвичайно особливими для кожного двигуна БД.
Hoagie

30
SARG = Пошук ARGument. Найсмішніше: "SARG" німецькою мовою означає "труну", тому мені завжди доводиться посміхатися, коли люди говорять про САРГАБЛІ - вміють покласти в труну? :-)
marc_s

здібність залежить від вашого оточення. Тут задокументовано MySQL: dev.mysql.com/doc/refman/5.0/uk/mysql-indexes.html
Френк Фермер

Маючи поля з вільним текстом замість "таблиць пошуку", це також суперечить духу зробити запит, який можна зрівняти. Користувачі неправильно написали речі під час введення вільного тексту (наприклад, назва міста), тоді як таблиці пошуку примушують користувачів вибрати правильно написану запис. Добре варто трохи зайвих проблем, адже це може бути правильно індексовано замість використання LIKE '% ...%' у присудку.
Інженер, що

Відповіді:


256

Найпоширеніша річ, яка зробить запит немарговим - це включити поле всередині функції у пункті, де:

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()) 

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? Мені якось сказав хлопець з оптимізації, що за допомогою АБО в пункті де можна скасувати розміщення запитів ..?
High Plains Grifter

2
@HighPlainsGrifter ви повинні використовувати UNION ALL для цього запиту - союз має неявну різницю, що робить запит набагато дорожчим, ніж потрібно, коли вам доведеться взаємовиключні набори даних
Девін Ламот,

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

Для того, щоб операцію вважали зручною, недостатньо, щоб вона могла просто використовувати наявний індекс. У наведеному вище прикладі додавання виклику функції проти індексованого стовпця в пункті, де, швидше за все, скористається певною перевагою визначеного індексу. Він буде "сканувати" aka вилучити всі значення з цього стовпця (індексу), а потім усуне ті, які не відповідають вказаному значенню фільтра. Він все ще недостатньо ефективний для таблиць з великою кількістю рядків. Що насправді визначає sragability, це можливість запиту переходити індекс b-tree за допомогою методу двійкового пошуку, який спирається на напівзадане видалення для масиву відсортованих елементів. У SQL він відображатиметься на плані виконання як "пошук пошуку".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.