Равно (=) против LIKE

282

При использовании SQL, есть ли какие-либо преимущества использования =в WHEREпредложении вместо LIKE?

Без каких-либо специальных операторов, LIKEи =так же, верно?

Travis
источник
4
Может быть, вы хотите указать тип БД ... mssql, mysql, oracle?
Аллен Райс
1
Ваш вопрос имеет по крайней мере 5голоса для тега like-operator . Могу ли я попросить вас предложить sql-like как синоним ?
Кермит,
@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, то символ pad является зависящим от реализации символом, отличным от любого символа в наборе символов X и Y, который сопоставляется меньше, чем любая строка в CS. В противном случае символ пэда - это.

б) Результат сравнения 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 или более смежных <символьных представлений> из M, и каждая <символьная репрезентация> из M является частью ровно одной подстроки.

ii) Если указатель i-й подстроки P является спецификатором произвольного символа, то i-ая подстрока M является любой отдельной <символьным представлением>.

iii) Если i-ый подстрока P является произвольным строковым спецификатором, то i-ая подстрока M является любой последовательностью из 0 или более <символьных представлений> s.

iv) Если i-й указатель подстроки в P не является ни указателем произвольного символа, ни указателем произвольной строки, то i-ая подстрока M равна этому указателю подстроки в соответствии с последовательностью упорядочения <like-предиката>, без добавление символов <пробел> к 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без %или с _настоящим совсем не то же самое, что использование =. Пусть ваш ответ получит тысячу голосов.
Риного
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 тоже.
Джоан
170

Оператор equals (=) представляет собой «оператор сравнения сравнивает два значения на равенство». Другими словами, в выражении SQL он не вернет true, если обе стороны уравнения не равны. Например:

SELECT * FROM Store WHERE Quantity = 200;

Оператор LIKE «реализует сравнение сопоставления с шаблоном», который пытается сопоставить «строковое значение со строкой шаблона, содержащей символы подстановки». Например:

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

LIKE обычно используется только со строками и равно (я считаю) быстрее. Оператор equals обрабатывает символы подстановки как буквенные символы. Разница в результатах возвращается следующим образом:

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».

Надеюсь, это поможет. Некоторая хорошая информация может быть найдена здесь .

achinda99
источник
108
У меня сложилось впечатление, что ОП знает, когда использовать LIKE и когда использовать =, ему просто интересно, есть ли разница в производительности, когда нет подстановочного знака. Этот ответ кратко затрагивает это, но я чувствую, что 95% этого ответа не очень актуальны.
Outlaw Programmer
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 'like' vs '=' performance :

Личный пример использования mysql 5.5: у меня было внутреннее соединение между 2 таблицами, одной из 3 миллионов строк и одной из 10 тысяч строк.

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

where login like '12345678'

используя 'объяснение' я получаю:

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

При использовании «=» в том же запросе это заняло около 0,1 секунды:

where login ='12345678'

Используя 'объяснение' я получаю:

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

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

Арис
источник
17

LIKEи =разные. LIKEэто то, что вы будете использовать в поисковом запросе. Это также позволяет использовать подстановочные знаки, такие как _(простой символьный символ) и %(многосимвольный символ).

= следует использовать, если вы хотите точные совпадения, и это будет быстрее.

Этот сайт объясняет LIKE

WalterJ89
источник
11

Одно из отличий - помимо возможности использовать подстановочные знаки с LIKE - заключается в конечных пробелах: оператор = игнорирует конечный пробел, но LIKE - нет.

МСВ
источник
4
Хотя это верно для MySQL и MS SQL, это не для PostgreSQL.
Бруно
10

Зависит от системы баз данных.

Обычно без специальных символов, да, = и LIKE одинаковы.

Однако некоторые системы баз данных могут по-разному относиться к настройкам сопоставления с разными операторами.

Например, в MySQL сравнения со строками = on всегда по умолчанию не чувствительны к регистру, поэтому LIKE без специальных символов одинаков. В некоторых других СУБД LIKE нечувствителен к регистру, а = нет.

ʞɔıu
источник
Есть ли что-то вроде обзора этой странности?
Гамбо
9

Для этого примера мы считаем само собой разумеющимся, что varcharcol не содержит ''и не имеет пустой ячейки против этого столбца

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

Первое приводит к выводу 0 строк, а второе показывает весь список. = строго совпадает с регистром, в то время как похоже действует как фильтр. если фильтр не имеет критериев, все данные действительны.

like - в силу своего назначения работает немного медленнее и предназначен для использования с varchar и подобными данными.

Арнаб
источник
6

Если вы ищете точное совпадение, вы можете использовать оба, = и LIKE.

Использование «=» в этом случае немного быстрее (поиск точного соответствия) - вы можете проверить это самостоятельно, дважды выполнив один и тот же запрос в SQL Server Management Studio, один раз - «=», один раз - «LIKE», и затем с помощью «Запрос» / «Включить фактический план выполнения».

Выполните два запроса, и вы должны увидеть результаты дважды, а также два фактических плана выполнения. В моем случае они были разделены на 50% против 50%, но план выполнения «=» имеет меньшую «оценочную стоимость поддерева» (отображается при наведении курсора на крайнее левое поле «ВЫБОР»), но опять же, это действительно не огромная разница.

Но когда вы начнете искать с подстановочными знаками в выражении LIKE, производительность поиска снизится. Поиск "LIKE Mill%" все еще может быть довольно быстрым - SQL Server может использовать индекс для этого столбца, если он есть. Поиск «LIKE% expression%» ужасно медленный, поскольку единственный способ, которым SQL Server может удовлетворить этот поиск, - выполнить полное сканирование таблицы. Так что будьте осторожны с вашими как!

Марк

marc_s
источник
-1 нет, это не всегда чуть-чуть быстрее. Если столбец индексируется с использованием% mystring%, это на несколько порядков медленнее. Действительно, любые стандарты кода, достойные их внимания, будут иметь строгие рекомендации о том, когда и когда не следует использовать их, например, в базе данных размером с микки-мышь.
Cruachan
1
Я никогда не говорил, что это будет чуть-чуть медленнее для всех случаев - я сказал, что это будет чуть-чуть медленнее, если вы будете искать ТОЧНОЕ совпадение. Конечно, поиск с помощью LIKE и использование подстановочных знаков, особенно в начале и конце вашего элемента поиска, НАМНОГО медленнее, без сомнения об этом.
marc_s
И да, я согласен - нужно иметь четкие рекомендации относительно того, когда использовать LIKE или нет (только когда вам НУЖНО искать с подстановочными знаками). Но опять же - теоретически, нет никакой разницы между теорией и практикой, но на практике .......
marc_s
6

Использование = позволяет избежать конфликтов символов подстановки и специальных символов в строке при построении запроса во время выполнения.

Это облегчает жизнь программиста, так как не требуется экранировать все специальные символы подстановки, которые могут появиться в предложении LIKE, и не дает ожидаемого результата. В конце концов, = 99% сценария использования, было бы больно каждый раз избегать их.

закатывает глаза в 90-х

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

Coincoin
источник
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

Может также быть незначительная разница в создании плана запроса при использовании "=" против "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".

Bruno
источник
2

К ключевому слову LIKE, несомненно, прилагается «ценник эффективности». Тем не менее, если у вас есть поле ввода, которое может включать символы подстановки, которые будут использоваться в вашем запросе, я бы рекомендовал использовать LIKE, только если вход содержит один из символов подстановки. В противном случае используйте стандарт, равный для сравнения.

С уважением...

Джош Стодола
источник
1

На самом деле все сводится к тому, что вы хотите сделать запрос. Если вы имеете в виду точное совпадение, используйте =. Если вы имеете в виду нечеткое совпадение, используйте LIKE. Сказать, что вы имеете в виду, обычно хорошая политика с кодом.

нет нет
источник
1

В Oracle «like» без подстановочных знаков вернет тот же результат, что и «equals», но может потребовать дополнительной обработки. По словам Тома Кайта , Oracle будет использовать «подобное» без подстановочных знаков как «равно» при использовании литералов, но не при использовании переменных связывания.

Крис Б
источник
0

=и LIKEне то же самое;

  1. = соответствует точной строке
  2. LIKE соответствует строке, которая может содержать символы подстановки (%)
Baretta
источник
2
Недостаточный ответ
Его можно использовать без подстановочных знаков. Вопрос задавал различия для тех же случаев.
М-Разави