Дорівнює (=) проти LIKE


281

Чи використовуєте SQL переваги використання =в WHEREпункті замість LIKE?

Без жодних спеціальних операторів, LIKEі =це те саме, правда?


4
Ви можете вказати тип db ... mssql, mysql, oracle?
Аллен Райс

1
У вашому запитанні є щонайменше 5голосів за тег оператора . Чи можу я просити Вас , що ви пропонуєте SQL-подібний як синонім ?
Керміт

@FreshPrinceOfSO, я зроблю це, коли отримаю достатньо репутації. Дякую.
Тревіс

Відповіді:


271

Різні оператори

LIKEі =є різними операторами. Більшість відповідей тут зосереджені на підтримці підстановки, що не є єдиною різницею між цими операторами!

=є оператором порівняння, який працює на числах і рядках. При порівнянні рядків оператор порівняння порівнює цілі рядки .

LIKE- це рядковий оператор, який порівнює символи за символами .

Для ускладнення питань обидва оператори використовують зіставлення, яке може мати важливий вплив на результат порівняння.

Мотиваційний приклад

Давайте спочатку визначимо приклад, коли ці оператори дають очевидно різні результати. Дозвольте мені цитувати з посібника MySQL:

Відповідно до стандарту SQL, LIKE виконує зіставлення на основі символів, таким чином, він може отримувати результати, відмінні від оператора порівняння =

mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
+-----------------------------------------+
| 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
+-----------------------------------------+
|                                       0 |
+-----------------------------------------+
mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
+--------------------------------------+
| 'ä' = 'ae' COLLATE latin1_german2_ci |
+--------------------------------------+
|                                    1 |
+--------------------------------------+

Зверніть увагу, що ця сторінка посібника MySQL називається функціями порівняння рядків і =не обговорюється, що означає, що =це не суворо функція порівняння рядків.

Як =працює?

SQL Standard § 8.2 описує , як =порівнюються рядки:

Порівняння двох символьних рядків визначається наступним чином:

a) Якщо довжина символів X не дорівнює довжині символів Y, то коротша рядок ефективно замінюється, для порівняння, копією самої себе, яка була подовжена на довжину довшого рядка шляхом конкатенації праворуч від одного або декількох символів колодки, де символ накладки вибирається на основі CS. Якщо CS має атрибут NO PAD, то символ накладки - це символ, що залежить від реалізації, відмінний від будь-якого символу в наборі символів X і Y, який згортається менше, ніж будь-який рядок під CS. В іншому випадку символом колодки є "a".

б) Результат порівняння X і Y дається послідовністю згортання CS.

c) Залежно від послідовності згортання, два рядки можуть порівнюватися рівними, навіть якщо вони різної довжини або містять різні послідовності символів. Коли операції MAX, MIN, DISTINCT посилаються на стовпчик угруповання та оператори UNION, EXCEPT та INTERSECT посилаються на символьні рядки, конкретне значення, вибране цими операціями з набору таких рівних значень, залежить від реалізації.

(Наголос додано.)

Що це означає? Це означає, що при порівнянні рядків =оператор - це лише тонка обгортка навколо поточного зіставлення. Порівнювання - це бібліотека, яка має різні правила порівняння рядків. Ось приклад двійкового зіставлення з MySQL :

static int my_strnncoll_binary(const CHARSET_INFO *cs __attribute__((unused)),
                               const uchar *s, size_t slen,
                               const uchar *t, size_t tlen,
                               my_bool t_is_prefix)
{
  size_t len= MY_MIN(slen,tlen);
  int cmp= memcmp(s,t,len);
  return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
}

Цей конкретний показник порівнює байт-байт (саме тому його називають "бінарним" - він не надає особливого значення рядкам). Інші порівняння можуть забезпечити більш розширені порівняння.

Наприклад, ось зіставлення UTF-8, яке підтримує порівнянні з регістром порівняння. Код занадто довгий, щоб вставити сюди, але перейдіть за цим посиланням і прочитайте корпус my_strnncollsp_utf8mb4(). Це порівняння може обробляти кілька байтів одночасно, і воно може застосовувати різні перетворення (наприклад, порівняння з невідчутливим випадком). =Оператор повністю абстрагується від примх узагальнення.

Як LIKEпрацює?

SQL Standard § 8.5 описує , як LIKEпорівнюються рядки:

<Передбачення>

M LIKE P

вірно, якщо існує розподіл M на підрядки таким чином:

i) Підрядка M - це послідовність з 0 або більше суміжних <символів представлення> s M, і кожне <представлення символів> M є частиною рівно однієї підрядки.

ii) Якщо специфікатор i-го підрядка P є довільним специфікатором символів, i-та підрядка M є будь-яким одиничним <представленням символів>.

iii) Якщо специфікатор i-го підрядка P є довільним специфікатором рядків, то i-та підрядка M - це будь-яка послідовність 0 або більше <представлення символів> s.

iv) Якщо специфікатор i-ої підрядки P не є ні довільним специфікатором символів, ні специфікатором довільної рядки, то i-та підрядка M дорівнює цьому специфікатору підрядків відповідно до послідовності згортання <подібного предиката>, без додавання символів <пробіл> до M і має таку ж довжину, що і специфікатор підрядки.

v) Кількість підрядків M дорівнює кількості специфікаторів підрядків P.

(Наголос додано.)

Це досить багатослівно, тому давайте розбимо його. Пункти ii і iii відносяться до підстановних знаків _і %, відповідно. Якщо Pжодні символи не містять, застосовується лише пункт iv. Це випадок інтересу, який викликає ОП.

У цьому випадку вона порівнює кожну "підрядку" (окремі символи) Mпроти кожної підрядки, Pвикористовуючи поточне порівняння.

Висновки

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

Який з них слід використовувати? Ніхто не може сказати вам цього - вам потрібно скористатися правильним для вашого випадку використання. Не передчасно оптимізуйте, перемикаючи оператори порівняння.


4
"EQUALS порівнює два фрагменти байта даних за байтом": спрощений і занадто часто не відповідає дійсності, тому що поведінка EQUALS (=) може бути змінена COLLATE, внаслідок чого класи символів порівнюються замість символів. Наприклад, див. Dev.mysql.com/doc/refman/5.0/en/charset-collate.html (MySQL) або sqlmag.com/blog/forcing-collation-where-clause-22-jun-2011 (SQL Server).
Пітер Б

11
Це правильна відповідь. Ми знаємо, що LIKEробить, але ця відповідь приголомшливо пояснює, що використання LIKEбез %або _присутніх зовсім не те саме, що використання =. Нехай ваша відповідь отримає тисячу грошей.
rinogo

1
@mehase це не може бути правдою. Якщо моє поле varchar містить значення 'AbCdEfG', а я це роблю WHERE MyCol = 'abcdefg', я все одно повертаю цей рядок назад, хоча вони явно не є байт-байтовим еквівалентом
Kip

1
І PeterB, і @Kip піднімають хороші бали. Я вдосконалив свою відповідь, щоб спробувати пояснити, як співставлення впливає на цих операторів.
Марк Е. Хааз

2
Це більше не здається істинним: set charset latin1; SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;дає 0, а також SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;0.
joanq

170

Оператор рівняння (=) - це "оператор порівняння, який порівнює два значення для рівності". Іншими словами, в операторі SQL він не поверне справжнє значення, якщо обидві сторони рівняння не рівні. Наприклад:

SELECT * FROM Store WHERE Quantity = 200;

Оператор LIKE "реалізує порівняння відповідності шаблону", яке намагається зіставити "значення рядка з рядком шаблону, що містить символи підстановки". Наприклад:

SELECT * FROM Employees WHERE Name LIKE 'Chris%';

LIKE, як правило, використовується лише з рядками, а рівне (я вважаю) швидше. Оператор рівних відноситься до символів, що знаходяться з підказкою, як буквальних символів. Різниця у повернених результатах полягає в наступному:

SELECT * FROM Employees WHERE Name = 'Chris';

І

SELECT * FROM Employees WHERE Name LIKE 'Chris';

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

SELECT * FROM Employees WHERE Name = 'Chris%';

І

SELECT * FROM Employees WHERE Name LIKE 'Chris%';

Повертає різні результати, коли використання "=" призводить до результатів лише з поверненням "Chris%", а оператор LIKE поверне все, що починається з "Chris".

Сподіваюся, що це допомагає. Деякі гарні відомості можна знайти тут .


108
Мені здається, що ОП знає, коли використовувати LIKE, а коли використовувати =, він просто цікавиться, чи є різниця в продуктивності, коли немає підстановки. Ця відповідь коротко стосується цього, але я вважаю, що 95% цієї відповіді не є дійсно актуальною.
Програматор поза законом

1
Дуже правильно. Я не впевнений, чи було це питання таким же, коли я відповів на нього. Якщо це було, я пропустив ту частину, яка запитала про виступ. Дякую за спостереження.
achinda99

9
Ця відповідь жахлива. LIKE і '=' є абсолютно різними операторами, але просто трапляється так само у деяких невеликих підмножинах випадків. Для нащадків прочитайте решту відповідей тут або, принаймні, google за "mysql like", перш ніж зробити це на пам'ять.
Марк Е. Хааз

3
З іншого боку, ця відповідь відповіла на запитання, яке я мав і гуглив. Іноді це так само добре, якщо відповідь відповідає заголовку питання, як і змісту.
CorayThan

Хороша думка пам'ятати, коли ви використовуєте char та varchar2. Якщо ви порівнюєте char із char. Перш ніж порівняти базу даних, спочатку перетворіть довжину першої 'змінної' на ту ж, що і друга. Якщо порівнювати char та varchar2, база даних нічого не зробить. docs.oracle.com/cd/A64702_01/doc/server.805/a58236/c_char.htm
xild

18

Це копія / вставка іншої моєї відповіді на питання SQL 'типу' vs '=' виконання :

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

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

where login like '12345678'

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

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

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

where login ='12345678'

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

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

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


17

LIKEі =різні. LIKEце те, що ви використовували б у пошуковому запиті. Він також дозволяє підкреслити символи типу _(простий символ символів) та %(багато символів підстановки).

= слід використовувати, якщо ви хочете точних відповідностей, і це буде швидше.

Цей сайт пояснює LIKE


11

Одна відмінність - окрім можливості використання шаблонів із LIKE - полягає у проміжках: Оператор = ігнорує простір, але LIKE цього не робить.


4
Хоча це стосується MySQL та MS SQL, це не стосується PostgreSQL.
Бруно

10

Залежить від системи баз даних.

Як правило, без спеціальних символів, так, = і LIKE однакові.

Деякі системи баз даних, однак, можуть по-різному ставитися до налаштувань порівняння з різними операторами.

Наприклад, у MySQL порівняння з = на рядках за замовчуванням завжди нечутливе до регістру, тому LIKE без спеціальних символів однаковий. У деяких інших RDBMS LIKE нечутливий до регістру, поки = ні.


Чи є щось подібне до огляду цієї дивацтва?
Gumbo

9

У цьому прикладі ми вважаємо, що varcharcol не містить ''і не має порожньої комірки проти цього стовпця

select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''

Перший приводить до виводу 0 рядків, а другий - весь список. = суворо збігається, хоча подібно до фільтру. якщо для фільтра немає критеріїв, всі дані є дійсними.

як - в силу своєї мети працює трохи повільніше і призначений для використання з варчаром та подібними даними.


6

Якщо ви шукаєте точну відповідність, ви можете використовувати обидва, = і LIKE.

Використання "=" є в цьому випадку трохи швидшим (пошук точної відповідності) - ви можете перевірити це самостійно, отримавши один і той же запит двічі в SQL Server Management Studio, один раз використовуючи "=", один раз використовуючи "LIKE" і потім використовуючи "Запит" / "Включити фактичний план виконання".

Виконайте два запити, і ви побачите свої результати двічі, плюс два фактичні плани виконання. У моєму випадку вони були розділені на 50% проти 50%, але план виконання "=" має меншу "орієнтовну вартість піддіаграми" (відображається, коли ви наведіть курсор на лівий край "ВИБІР") - але знову ж таки, це дійсно не величезна різниця.

Але коли ви почнете пошук за допомогою символів із символів у виразі LIKE, ефективність пошуку зменшиться. Пошук "LIKE Mill%" все ще може бути досить швидким - SQL Server може використовувати індекс у цьому стовпці, якщо такий є. Пошук "LIKE% express%" жахливо повільний, оскільки єдиний спосіб, коли SQL Server може задовольнити цей пошук, - це зробити повне сканування таблиці. Тож будьте обережні зі своїми лайками!

Марк


-1 як ні, це не завжди крихітний шматочок швидше. Якщо стовпчик індексується за допомогою% mystring%, це на пару порядків повільніше. Дійсно, будь-які стандарти коду, які варті їх солі, матимуть чіткі вказівки щодо того, коли і коли не використовувати, як на будь-якій більшій, ніж база даних з мишами.
Круачан

1
Я ніколи не казав, що це буде крихітніше повільніше для всіх випадків - я сказав, що це буде крихітніше повільніше, якщо шукати ТОЧНУЮ відповідність. Безперервно, пошук за допомогою LIKE та використання символів, особливо на початку та в кінці вашого пошукового елемента, набагато повільніше, в цьому немає сумнівів.
marc_s

І так, я погоджуюся - слід мати чіткі вказівки щодо того, коли використовувати LIKE чи ні (лише тоді, коли НЕОБХІДНО шукати підстановки). Але знову ж таки - в теорії немає різниці між теорією та практикою, а на практиці .......
marc_s

6

Використання = уникає символів підстановки та конфліктів спеціальних символів у рядку під час створення запиту під час виконання.

Це полегшує життя програміста, тому що не потрібно уникати всіх спеціальних символів, які можуть прослизати в пункті LIKE і не давати бажаного результату. Зрештою, = це сценарій використання 99% випадків, болісно кожного разу уникати їх.

закочує очі в 90-х

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


6

Для вирішення оригінального питання щодо продуктивності зводиться до використання індексу . При простому скануванні таблиці "LIKE" і "=" ідентичні . Якщо задіяні індекси, це залежить від того, як формується пункт LIKE. Більш конкретно, яке місце розміщення підстановок (-ів)?


Розглянемо наступне:

CREATE TABLE test(
    txt_col  varchar(10) NOT NULL
)
go

insert test (txt_col)
select CONVERT(varchar(10), row_number() over (order by (select 1))) r
  from master..spt_values a, master..spt_values b
go

CREATE INDEX IX_test_data 
    ON test (txt_col);
go 

--Turn on Show Execution Plan
set statistics io on

--A LIKE Clause with a wildcard at the beginning
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '%10000'
--Results in
--Table 'test'. Scan count 3, logical reads 15404, physical reads 2, read-ahead reads 15416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index SCAN is 85% of Query Cost

--A LIKE Clause with a wildcard in the middle
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '1%99'
--Results in
--Table 'test'. Scan count 1, logical reads 3023, physical reads 3, read-ahead reads 3018, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost for test data, but it may result in a Table Scan depending on table size/structure

--A LIKE Clause with no wildcards
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO

--an "=" clause = does Index Seek same as above
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col = '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO


DROP TABLE test

Можливо, також існує незначна різниця у створенні плану запитів при використанні "=" vs "LIKE".


4

Крім підстановок, різниця між =AND LIKEбуде залежати як від типу SQL-сервера, так і від типу стовпця.

Візьмемо цей приклад:

CREATE TABLE testtable (
  varchar_name VARCHAR(10),
  char_name CHAR(10),
  val INTEGER
);

INSERT INTO testtable(varchar_name, char_name, val)
    VALUES ('A', 'A', 10), ('B', 'B', 20);

SELECT 'VarChar Eq Without Space', val FROM testtable WHERE varchar_name='A'
UNION ALL
SELECT 'VarChar Eq With Space', val FROM testtable WHERE varchar_name='A '
UNION ALL
SELECT 'VarChar Like Without Space', val FROM testtable WHERE varchar_name LIKE 'A'
UNION ALL
SELECT 'VarChar Like Space', val FROM testtable WHERE varchar_name LIKE 'A '
UNION ALL
SELECT 'Char Eq Without Space', val FROM testtable WHERE char_name='A'
UNION ALL
SELECT 'Char Eq With Space', val FROM testtable WHERE char_name='A '
UNION ALL
SELECT 'Char Like Without Space', val FROM testtable WHERE char_name LIKE 'A'
UNION ALL
SELECT 'Char Like With Space', val FROM testtable WHERE char_name LIKE 'A '
  • Використовуючи MS SQL Server 2012 , проміжки проміжку будуть ігноруватися при порівнянні, за винятком випадків, LIKEколи тип стовпця VARCHAR.

  • Використовуючи MySQL 5.5 , проміжки пробігу будуть ігноровані для =, але не для LIKE, і з CHARі VARCHAR.

  • Використовуючи PostgreSQL 9.1 , пробіли є значущими як для обох, так =і для LIKEвикористання VARCHAR, але не для них CHAR(див. Документацію ).

    Поведінка з LIKEтакож відрізняється від CHAR.

    Використання тих же даних, що і вище, використання явного CASTназви стовпця також має значення :

    SELECT 'CAST none', val FROM testtable WHERE char_name LIKE 'A'
    UNION ALL
    SELECT 'CAST both', val FROM testtable WHERE
        CAST(char_name AS CHAR) LIKE CAST('A' AS CHAR)
    UNION ALL
    SELECT 'CAST col', val FROM testtable WHERE CAST(char_name AS CHAR) LIKE 'A'
    UNION ALL
    SELECT 'CAST value', val FROM testtable WHERE char_name LIKE CAST('A' AS CHAR)

    Це повертає лише рядки для "CAST і" та "CAST col".


2

Ключове слово LIKE, безсумнівно, постачається із доданою "ціною ефективності". Це означає, що якщо у вас є поле для введення, яке потенційно може включати символи підказки, які будуть використані у вашому запиті, я рекомендую використовувати LIKE, лише якщо вхід містить одну з підстановок. В іншому випадку використовуйте стандарт, рівний порівнянню.

З найкращими побажаннями...


1

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


1

В Oracle, "подібний" без жодних символів поверне той же результат, що і "рівний", але може вимагати додаткової обробки. За словами Тома Кейта , Oracle трактуватиме "як", що не має символів, як "рівним", коли використовує літерали, але не при використанні змінних прив'язки.


0

=і LIKEне однаковий;

  1. = відповідає точному рядку
  2. LIKE відповідає рядку, який може містити символи (%)

2
Недостатня відповідь

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