Чи використовуєте SQL переваги використання =
в WHERE
пункті замість LIKE
?
Без жодних спеціальних операторів, LIKE
і =
це те саме, правда?
5
голосів за тег оператора . Чи можу я просити Вас , що ви пропонуєте SQL-подібний як синонім ?
Чи використовуєте SQL переваги використання =
в WHERE
пункті замість LIKE
?
Без жодних спеціальних операторів, LIKE
і =
це те саме, правда?
5
голосів за тег оператора . Чи можу я просити Вас , що ви пропонуєте SQL-подібний як синонім ?
Відповіді:
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
порівнюючи один символ за один раз. Обидва порівняння використовують поточне порівняння. Ця різниця призводить до різних результатів у деяких випадках, про що свідчить перший приклад у цій публікації.
Який з них слід використовувати? Ніхто не може сказати вам цього - вам потрібно скористатися правильним для вашого випадку використання. Не передчасно оптимізуйте, перемикаючи оператори порівняння.
LIKE
робить, але ця відповідь приголомшливо пояснює, що використання LIKE
без %
або _
присутніх зовсім не те саме, що використання =
. Нехай ваша відповідь отримає тисячу грошей.
'AbCdEfG'
, а я це роблю WHERE MyCol = 'abcdefg'
, я все одно повертаю цей рядок назад, хоча вони явно не є байт-байтовим еквівалентом
set charset latin1;
SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
дає 0, а також SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
0.
Оператор рівняння (=) - це "оператор порівняння, який порівнює два значення для рівності". Іншими словами, в операторі 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".
Сподіваюся, що це допомагає. Деякі гарні відомості можна знайти тут .
Це копія / вставка іншої моєї відповіді на питання SQL 'типу' vs '=' виконання :
Особистий приклад з використанням mysql 5.5: У мене було внутрішнє з'єднання між двома таблицями, однією з 3 мільйонів рядків і однією з 10 тисяч рядків.
Використовуючи подібне в індексі, як показано нижче (ніяких підстановок), це зайняло приблизно 30 секунд:
where login like '12345678'
за допомогою "пояснення" я отримую:
Використовуючи '=' для того самого запиту, це зайняло приблизно 0,1 секунди:
where login ='12345678'
Використовуючи "пояснити", я отримую:
Як бачимо, like
повністю скасовано пошук індексу, тому запит зайняв у 300 разів більше часу.
LIKE
і =
різні. LIKE
це те, що ви використовували б у пошуковому запиті. Він також дозволяє підкреслити символи типу _
(простий символ символів) та %
(багато символів підстановки).
=
слід використовувати, якщо ви хочете точних відповідностей, і це буде швидше.
Залежить від системи баз даних.
Як правило, без спеціальних символів, так, = і LIKE однакові.
Деякі системи баз даних, однак, можуть по-різному ставитися до налаштувань порівняння з різними операторами.
Наприклад, у MySQL порівняння з = на рядках за замовчуванням завжди нечутливе до регістру, тому LIKE без спеціальних символів однаковий. У деяких інших RDBMS LIKE нечутливий до регістру, поки = ні.
У цьому прикладі ми вважаємо, що varcharcol не містить ''
і не має порожньої комірки проти цього стовпця
select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''
Перший приводить до виводу 0 рядків, а другий - весь список. = суворо збігається, хоча подібно до фільтру. якщо для фільтра немає критеріїв, всі дані є дійсними.
як - в силу своєї мети працює трохи повільніше і призначений для використання з варчаром та подібними даними.
Якщо ви шукаєте точну відповідність, ви можете використовувати обидва, = і LIKE.
Використання "=" є в цьому випадку трохи швидшим (пошук точної відповідності) - ви можете перевірити це самостійно, отримавши один і той же запит двічі в SQL Server Management Studio, один раз використовуючи "=", один раз використовуючи "LIKE" і потім використовуючи "Запит" / "Включити фактичний план виконання".
Виконайте два запити, і ви побачите свої результати двічі, плюс два фактичні плани виконання. У моєму випадку вони були розділені на 50% проти 50%, але план виконання "=" має меншу "орієнтовну вартість піддіаграми" (відображається, коли ви наведіть курсор на лівий край "ВИБІР") - але знову ж таки, це дійсно не величезна різниця.
Але коли ви почнете пошук за допомогою символів із символів у виразі LIKE, ефективність пошуку зменшиться. Пошук "LIKE Mill%" все ще може бути досить швидким - SQL Server може використовувати індекс у цьому стовпці, якщо такий є. Пошук "LIKE% express%" жахливо повільний, оскільки єдиний спосіб, коли SQL Server може задовольнити цей пошук, - це зробити повне сканування таблиці. Тож будьте обережні зі своїми лайками!
Марк
Використання = уникає символів підстановки та конфліктів спеціальних символів у рядку під час створення запиту під час виконання.
Це полегшує життя програміста, тому що не потрібно уникати всіх спеціальних символів, які можуть прослизати в пункті LIKE і не давати бажаного результату. Зрештою, = це сценарій використання 99% випадків, болісно кожного разу уникати їх.
закочує очі в 90-х
Я також підозрюю, що це трохи повільніше, але я сумніваюся, що це важливо, якщо в шаблоні немає ніяких символів.
Для вирішення оригінального питання щодо продуктивності зводиться до використання індексу . При простому скануванні таблиці "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".
Крім підстановок, різниця між =
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".
Ключове слово LIKE, безсумнівно, постачається із доданою "ціною ефективності". Це означає, що якщо у вас є поле для введення, яке потенційно може включати символи підказки, які будуть використані у вашому запиті, я рекомендую використовувати LIKE, лише якщо вхід містить одну з підстановок. В іншому випадку використовуйте стандарт, рівний порівнянню.
З найкращими побажаннями...
В Oracle, "подібний" без жодних символів поверне той же результат, що і "рівний", але може вимагати додаткової обробки. За словами Тома Кейта , Oracle трактуватиме "як", що не має символів, як "рівним", коли використовує літерали, але не при використанні змінних прив'язки.