SQL 'як' проти '=' продуктивність


82

Це питання обходить те, що мені цікаво, але відповіді точно не стосуються цього.

Здавалося б, що загалом '=' швидше, ніж 'подобається' при використанні символів підстановки. Здається, це загальноприйнята мудрість. Однак, припустимо, у мене є стовпець, що містить обмежену кількість різних фіксованих, жорстко закодованих ідентифікаторів varchar, і я хочу виділити всі рядки, що відповідають одному з них:

select * from table where value like 'abc%'

і

select * from table where value = 'abcdefghijklmn'

"Подобається" потрібно лише протестувати перші три символи, щоб знайти відповідність, тоді як "=" має порівняти весь рядок. У цьому випадку мені здається, що "подобається" матиме перевагу за інших рівних умов.

Це задумано як загальне, академічне питання, і тому не має значення, яка БД, але воно виникло за допомогою SQL Server 2005.


23
Одне головне, що ви залишили поза увагою, value- індексується чи ні . Якщо це так, то =це простий пошук без необхідності сканування таблиці, який перевершить штани будь-якого LIKEтвердження, яке ви на нього кинете.
Даніель ДіПаоло,

7
@Daniel Я думаю, що це неправильно. A LIKEіз символом підстановки в кінці є SARGable і, отже, буде виконуватися пошук діапазону за індексом, сканування таблиці не видно. Цей пошук діапазону може досить зручно конкурувати з =твердженням, і у багатьох випадках (наприклад, якщо всі задовільні рядки знаходяться на одній сторінці, що є малоймовірною умовою) може бути точно така ж продуктивність, що спричиняє однакову кількість читань.
ErikE

Мій "за інших рівних рів" мав на меті висвітлити проблему "проіндексовано чи ні", але, мабуть, існують принаймні певні суперечки щодо того, наскільки велика різниця це матиме, відповідно до моїх коментарів щодо інших відповідей.
MickeyfAgain_BeforeExitOfSO

Дивіться мою відповідь. Спочатку я тестував неіндексовано, і продуктивність однакова (обидва сканування таблиць були абсолютно однаковими). Для свого тестового сценарію я припустив, що він буде проіндексовано, інакше чому б ви взагалі дбали про продуктивність?
JNK

5
Усі розмови про „подобається” у цьому питанні та відповіді змушують нас звучати як група дівчат середньої школи. Мовляв, цілком.
JulianR

Відповіді:


64

Див. Https://web.archive.org/web/20150209022016/http://myitforum.com/cs2/blogs/jnelson/archive/2007/11/16/108354.aspx

Цитата звідти:

правила використання індексу з LIKE такі:

  • Якщо у ваших критеріях фільтра використовується дорівнює = і поле індексується, то, швидше за все, воно буде використовувати ІНДЕКС / КЛАСТЕРОВАНИЙ ІНДЕКС ШУК

  • Якщо у ваших критеріях фільтра використовується LIKE, без підстановочних знаків (наприклад, якщо у вас у веб-звіті був параметр, МОЖИЙ мати%, але замість цього ви використовуєте повний рядок), це приблизно так само, як # 1, використовувати індекс. Збільшена вартість - майже нічого.

  • Якщо у ваших критеріях фільтра використовується LIKE, але з підстановкою на початку (як у Name0 LIKE '% UTER'), набагато менше шансів використовувати індекс, але він все одно може принаймні виконати INDEX SCAN на повному або частковому діапазоні індекс.

  • Втім, якщо ваш критерій фільтра використовує LIKE, але починається з STRING FIRST і має де-небудь символи підстановки ПІСЛЯ цього (як у Name0 LIKE 'COMP% ER'), тоді SQL може просто використовувати INDEX SEEK для швидкого пошуку рядків, які мають однакові перші початкові символи, а потім перегляньте ці рядки для точного збігу.

(Також майте на увазі, механізм SQL все одно може використовувати індекс не так, як ви очікуєте, залежно від того, що ще відбувається у вашому запиті та до яких таблиць ви приєднуєтеся. Механізм SQL залишає за собою право переписати ваші запитайте трохи, щоб отримати дані таким чином, який, на його думку, є найбільш ефективним, і який може включати ІНДЕКС-СКАН замість ІНДЕКС-ШУКУ)


1
це посилання мертве
baxx

2
@baxx копія посилання доступна в машині зворотного зв'язку. web.archive.org/web/20150209022016/http://myitforum.com/cs2/…
алфавіт 5

45

Це помітна різниця.

Запустіть наступне:

Create Table #TempTester (id int, col1 varchar(20), value varchar(20))
go

INSERT INTO #TempTester (id, col1, value)
VALUES
(1, 'this is #1', 'abcdefghij')
GO

INSERT INTO #TempTester (id, col1, value)
VALUES
(2, 'this is #2', 'foob'),
(3, 'this is #3', 'abdefghic'),
(4, 'this is #4', 'other'),
(5, 'this is #5', 'zyx'),
(6, 'this is #6', 'zyx'),
(7, 'this is #7', 'zyx'),
(8, 'this is #8', 'klm'),
(9, 'this is #9', 'klm'),
(10, 'this is #10', 'zyx')
GO 10000

CREATE CLUSTERED INDEX ixId ON #TempTester(id)CREATE CLUSTERED INDEX ixId ON #TempTester(id)

CREATE NONCLUSTERED INDEX ixTesting ON #TempTester(value)

Тоді:

SET SHOWPLAN_XML ON

Тоді:

SELECT * FROM #TempTester WHERE value LIKE 'abc%'

SELECT * FROM #TempTester WHERE value = 'abcdefghij'

Отриманий план виконання показує, що вартість першої операції, LIKEпорівняння, приблизно в 10 разів дорожча =порівняння.

Якщо ви можете скористатися =порівнянням, будь ласка, зробіть це.


2
+1 для фактичного тестування. Тільки дивлячись на план виставок, можливо, не розповість усієї історії. Я збираюся провести власне тестування і повідомлю всіх, якщо виявлю щось несподіване.
Tom H

1
Том - правда, але це дало мені достатньо вказівки на те, що обидва НЕ оброблялись однаково за кадром.
JNK

1
Витрати, показані в плані виконання, є помилковими. Вони не відображають фактичних показників. У першому плані вони базуються на розрахунковій кількості рядків, 19.95отже, витрати на SQL Server у додаткових 19 ключових пошуках, які ніколи не реалізуються фактично (Навіть у фактичному плані виконання вказані витрати базуються на Орієнтовній вартості піддерева)
Мартін Сміт

Я щойно провів ваш тест, а також один із приблизно 1 мільйоном рядків, і в обох випадках продуктивність та плани запитів були однаковими. Це на SQL 2008, оскільки у мене немає 2005 на цій машині.
Tom H

1
@JNK - щойно спробував - різниця незначна, однак диспропорція однакова. 327ms для LIKE, 203ms для =. Я сподіваюся, якщо б я провів більше тестів і взяв точні середні показники, не було б реальної різниці між #temp та реальною таблицею.
Буде

13

Ви також повинні пам’ятати, що під час використання likeдеякі варіанти sql ігноруватимуть індекси, що призведе до зниження продуктивності. Це особливо вірно, якщо ви не використовуєте шаблон "починається з", як ваш приклад.

Ви повинні реально поглянути на план виконання запиту і побачити, що він робить, гадати якомога менше.

Сказано, шаблон "починається з" може і оптимізується на сервері sql. Він буде використовувати індекс таблиці. EF 4,0 перемикається likeна StartsWithз цієї причини.


2
Жодна реляційна база даних, що не заслуговує на увагу, не буде ігнорувати індекс, якщо подібний шаблон є частиною запиту, а підстановка відстає. Це може бути інша історія, якщо ви прив'язуєте значення, а база даних підтримує прив'язку окремо від підготовки запиту.
Dave W. Smith

Це те, що мені каже і моя кишка, але я маю лише практичний досвід роботи з SQL-сервером у цьому плані, тому я зосередився на цьому спеціально.
Сліпий

7

Якщо valueнеіндексовано, обидва результати призводять до сканування таблиці. Різниця в продуктивності в цьому сценарії буде незначною.

Якщо valueіндексується, як зазначає Даніель у своєму коментарі, =результат призведе до пошуку індексу, що є продуктивністю O (log N). ЯК буде (швидше за все - в залежності від того, як воно селективного) в результаті часткового сканування індексу >= 'abc'і < 'abd'який зажадає більше зусиль , ніж =.

Зверніть увагу, що тут я говорю про SQL Server - не всі СУБД будуть приємні з LIKE.


Я не думаю, що ви знаєте, як працює двійковий пошук. І =випадок, і like '...%'випадок поводяться однаково, якщо sql розпізнає шаблон (і він це робить), оскільки в обох випадках піддерева вибираються на основі співвідношень порівняння.
Blindy

О, я люблю. LIKE, швидше за все, поводитиметься гірше, хоча все одно буде O (журнал N), якщо вибірковість досить висока - O (журнал N), щоб дізнатись, з чого почати часткове сканування, тоді ряд прямих читань через індекс до досягнуто кінцевої точки 'abd'.
Буде

Так, але приклад OP передбачає, що в цьому діапазоні є лише одне значення, тож, маючи це на увазі, порівняння будуть ідентичними.
Сліпий

Дійсний пункт - не зовсім зрозуміло, що саме про це говорив ОП, але я думаю, що це скоріше так, ніж ні. У цьому випадку продуктивність буде майже однаковою.
Буде

Шукання діапазону LIKE, швидше за все, досить зручно конкуруватиме з оператором =, і в багатьох випадках (наприклад, якщо всі задовольняючі рядки знаходяться на одній сторінці, що є малоймовірною умовою) може бути точно така ж продуктивність, що спричиняє однакову кількість читань . Я думаю, що сказати "вимагатиме більше зусиль" - це помилкова загальна заява.
ErikE

6

Ви ставите неправильне запитання. У базах даних не важлива продуктивність оператора, це завжди SARGability виразу та покривність загального запиту. Діяльність самого оператора в основному не має значення.

Отже, як LIKEі =порівняти з точки зору SARGability? LIKE, коли використовується з виразом, який не починається з константи (наприклад, коли використовується LIKE '%something'), за визначенням не є SARGabale. Але це робить =або LIKE 'something%'SARGable? Ні. Як і на будь-яке запитання щодо продуктивності SQL, відповідь не на запит тексту, а на розгорнуту схему. Ці вирази можуть бути SARGable, якщо для їх задоволення існує індекс.

Отже, по правді кажучи, між =і є невеликі відмінності LIKE. Але запитати, чи є один оператор чи інший оператор „швидшим” у SQL, все одно, що запитати „Що йде швидше, червона машина чи синя машина?”. Ви повинні задавати питання про розмір двигуна та вагу транспортного засобу, а не про колір ... Щоб підійти до питань щодо оптимізації реляційних таблиць, слід шукати свої індекси та вирази в реченні WHERE (та інших реченнях, але це зазвичай починається з ДЕ).


5

Особистий приклад використання mysql 5.5: У мене було внутрішнє з'єднання між 2 таблицями, однією з 3 мільйонів рядків і однією з 10 тисяч рядків.

При використанні подібного для індексу, як показано нижче (без підстановочних знаків), це зайняло близько 30 секунд:

where login like '12345678'

за допомогою "пояснити" я отримую:

введіть тут опис зображення

При використанні '=' для того самого запиту, це зайняло близько 0,1 секунди:

where login ='600009'

Використовуючи "пояснити", я отримую:

введіть тут опис зображення

Як бачите, пошук likeскасованого індексу повністю скасовано, тому запит зайняв у 300 разів більше часу.


Ви також можете просто переглянути план виконання, щоб підтвердити це
LittleBobbyTables - Au Revoir

дякую @LittleBobbyTables. Подивимось на це.
Aris

Не знаю, чи це пов’язано з моєю останньою версією (5.7), але LIKE не порушує тут мого унікального індексу.
Себас

0

Можливо, ви шукаєте повнотекстовий пошук .

На відміну від повнотекстового пошуку, предикат LIKE Transact-SQL працює лише на шаблонах символів. Крім того, ви не можете використовувати предикат LIKE для запиту відформатованих двійкових даних. Крім того, запит LIKE щодо великої кількості неструктурованих текстових даних набагато повільніший, ніж еквівалентний повнотекстовий запит щодо тих самих даних . Повторний запит щодо мільйонів рядків текстових даних може повернутися за хвилини; тоді як повнотекстовий запит може зайняти лише кілька секунд або менше щодо тих самих даних, залежно від кількості рядків, які повертаються.


-1

Насамперед ,

вони не завжди рівні

    select 'Hello' from dual where 'Hello  ' like 'Hello';

    select 'Hello' from dual where 'Hello  ' =  'Hello';

коли речі не завжди рівні, говорити про їх ефективність не так актуально.

Якщо ви працюєте над рядками та лише змінними char, тоді ви можете говорити про продуктивність. Але не використовуйте like і "=" як загальнозамінні.

Як ви могли б бачити у багатьох дописах (вище та інші запитання), у випадках, коли вони рівні, продуктивність подібних показників є повільнішою завдяки узгодженню шаблонів (сортування)


Якщо 'Hello 'є VARCHAR(за замовчуванням), ви маєте рацію, а якщо це так, CHARто ні. Киньте це на CHAR(7)і обидва повертаються істинними. Крім того, що, біса, ти робиш там, де не TRIMвводиш своїх варчарів? (примітка: це принаймні так у Росії SQL Server 2008r2)
abluejelly
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.