Sama dengan (=) vs. LIKE

282

Bila menggunakan SQL, apakah ada manfaat menggunakan =dalam WHEREklausul bukan LIKE?

Tanpa operator khusus, LIKEdan =apakah sama, kan?

Travis
sumber
4
Mungkin ingin menentukan tipe db ... mssql, mysql, oracle?
Allen Rice
1
Pertanyaan Anda setidaknya memiliki 5suara untuk tag seperti operator . Bisakah saya meminta Anda menyarankan seperti sql sebagai sinonim ?
Kermit
@FreshPrinceOfSO, saya akan melakukannya ketika saya mendapatkan reputasi yang cukup. Terima kasih.
Travis

Jawaban:

271

Operator yang berbeda

LIKE dan = merupakan operator yang berbeda. Sebagian besar jawaban di sini fokus pada dukungan wildcard, yang bukan satu-satunya perbedaan antara operator-operator ini!

=adalah operator perbandingan yang beroperasi pada angka dan string. Saat membandingkan string, operator perbandingan membandingkan seluruh string .

LIKEadalah operator string yang membandingkan karakter dengan karakter .

Untuk memperumit masalah, kedua operator menggunakan collation yang dapat memiliki efek penting pada hasil perbandingan.

Contoh Memotivasi

Mari kita pertama-tama mengidentifikasi contoh di mana operator ini menghasilkan hasil yang jelas berbeda. Izinkan saya mengutip dari manual MySQL:

Per standar SQL, LIKE melakukan pencocokan pada basis per karakter, sehingga ia dapat menghasilkan hasil yang berbeda dari operator = pembanding:

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 |
+--------------------------------------+

Harap dicatat bahwa halaman manual MySQL ini disebut String Comparison Functions , dan =tidak dibahas, yang menyiratkan hal itu= ini bukan semata-mata fungsi perbandingan string.

Bagaimana cara =kerjanya?

The SQL Standard § 8.2 menggambarkan bagaimana= membandingkan string:

Perbandingan dua string karakter ditentukan sebagai berikut:

a) Jika panjang karakter X tidak sama dengan panjang karakter Y, maka string yang lebih pendek secara efektif diganti, untuk tujuan perbandingan, dengan salinannya sendiri yang telah diperpanjang hingga panjang string yang lebih panjang. oleh penggabungan di sebelah kanan satu atau lebih karakter pad, di mana karakter pad dipilih berdasarkan CS. Jika CS memiliki atribut NO PAD, maka karakter pad adalah karakter yang bergantung pada implementasi yang berbeda dari karakter apa pun dalam set karakter X dan Y yang menyusun kurang dari string apa pun di bawah CS. Jika tidak, karakter pad adalah a.

b) Hasil perbandingan X dan Y diberikan oleh CS urutan sekuensing.

c) Bergantung pada urutan penyatuan, dua string dapat membandingkan sama bahkan jika mereka memiliki panjang yang berbeda atau mengandung urutan karakter yang berbeda. Ketika operasi MAX, MIN, DISTINCT, referensi ke kolom pengelompokan, dan operator UNION, KECUALI, dan INTERSECT mengacu pada string karakter, nilai spesifik yang dipilih oleh operasi ini dari serangkaian nilai yang sama bergantung pada implementasi.

(Penekanan ditambahkan.)

Apa artinya ini? Ini berarti bahwa ketika membandingkan string, =operator hanyalah pembungkus tipis di sekitar susunan saat ini. Kolasi adalah perpustakaan yang memiliki berbagai aturan untuk membandingkan string. Berikut adalah contoh pengumpulan biner dari 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);
}

Susunan khusus ini terjadi untuk membandingkan byte-by-byte (itulah sebabnya ini disebut "biner" - tidak memberikan makna khusus pada string). Koleksi lainnya dapat memberikan perbandingan yang lebih maju.

Misalnya, berikut ini adalah susunan UTF-8 yang mendukung perbandingan case-insensitive. Kode ini terlalu panjang untuk ditempelkan di sini, tetapi buka tautan itu dan baca isi my_strnncollsp_utf8mb4(). Susunan ini dapat memproses beberapa byte sekaligus dan dapat menerapkan berbagai transformasi (seperti perbandingan tidak sensitif huruf). Itu= operator benar-benar disarikan dari keanehan pemeriksaan tersebut.

Bagaimana LIKEkerjanya?

The SQL Standard § 8,5 menjelaskan bagaimana LIKEmembandingkan string:

The <predicate>

M LIKE P

benar jika ada partisi M menjadi substring sehingga:

i) Substring M adalah urutan 0 atau lebih berdekatan <representasi karakter> s dari M dan setiap <representasi karakter> M adalah bagian dari satu substring.

ii) Jika specifier substring ke-i dari P adalah specifier karakter yang berubah-ubah, substring ke-i dari M adalah sembarang <representasi karakter> tunggal.

iii) Jika specifier substring ke-i dari P adalah specifier string arbitrer, maka substring ke-i dari M adalah setiap urutan 0 atau lebih <representasi karakter> s.

iv) Jika specifier substring ke-i dari P bukanlah specifier karakter arbitrer atau specifier string arbitrer, maka substring ke-i dari M sama dengan specifier substring tersebut sesuai dengan urutan susunan <predikat seperti>, tanpa menambahkan karakter <spasi> ke M, dan memiliki panjang yang sama dengan specifier substring itu.

v) Jumlah substring M sama dengan jumlah penentu substring P.

(Penekanan ditambahkan.)

Ini cukup bertele-tele, jadi mari kita jabarkan. Item ii dan iii merujuk ke wildcard _dan %, masing-masing. Jika Ptidak mengandung wildcard, maka hanya item iv yang berlaku. Ini adalah kasus bunga yang ditimbulkan oleh OP.

Dalam hal ini, ia membandingkan setiap "substring" (karakter individu) Mterhadap setiap substring dalam Pmenggunakan susunan saat ini.

Kesimpulan

Intinya adalah ketika membandingkan string, =membandingkan seluruh string sambil LIKEmembandingkan satu karakter pada suatu waktu. Kedua perbandingan menggunakan susunan saat ini. Perbedaan ini menyebabkan hasil yang berbeda dalam beberapa kasus, sebagaimana dibuktikan dalam contoh pertama dalam posting ini.

Yang mana yang harus Anda gunakan? Tidak ada yang bisa memberi tahu Anda - Anda perlu menggunakan yang benar untuk use case Anda. Jangan mengoptimalkan secara prematur dengan mengganti operator perbandingan.

Mark E. Haase
sumber
4
"EQUALS membandingkan dua potong data byte demi byte": terlalu disederhanakan, dan terlalu sering tidak benar, karena perilaku EQUALS (=) dapat dimodifikasi dengan COLLATE, menyebabkan kelas karakter dibandingkan bukan karakter. Misalnya, lihat dev.mysql.com/doc/refman/5.0/en/charset-collate.html (MySQL) atau sqlmag.com/blog/forcing-collation-where-clause-22-jun-2011 (SQL Server).
Peter B
11
Ini jawaban yang benar. Kita tahu apa yang LIKEdilakukan, tetapi jawaban ini dengan luar biasa menjelaskan bahwa menggunakan LIKEtanpa %atau _hadir sama sekali tidak sama dengan menggunakan =. Semoga jawaban Anda menerima seribu upvotes.
rinogo
1
@maseangkan ini tidak mungkin benar. Jika bidang varchar saya berisi nilai 'AbCdEfG', dan saya lakukan WHERE MyCol = 'abcdefg', saya masih mendapatkan baris itu kembali, meskipun mereka jelas tidak setara byte-by-byte
Kip
1
PeterB dan @Kip keduanya meningkatkan poin bagus. Saya telah meningkatkan jawaban saya untuk mencoba menjelaskan bagaimana collation memengaruhi operator ini.
Mark E. Haase
2
Ini sepertinya tidak benar lagi: set charset latin1; SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;memberi 0, dan SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;memberi 0 juga.
joanq
170

Operator equals (=) adalah "operator perbandingan membandingkan dua nilai untuk kesetaraan." Dengan kata lain, dalam pernyataan SQL, itu tidak akan kembali benar kecuali kedua sisi persamaan sama. Sebagai contoh:

SELECT * FROM Store WHERE Quantity = 200;

Operator LIKE "mengimplementasikan perbandingan kecocokan pola" yang mencoba untuk mencocokkan "nilai string terhadap string pola yang berisi karakter wild-card." Sebagai contoh:

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

LIKE umumnya hanya digunakan dengan string dan equals (saya percaya) lebih cepat. Operator yang sama memperlakukan karakter wild card sebagai karakter literal. Perbedaan dalam hasil yang dikembalikan adalah sebagai berikut:

SELECT * FROM Employees WHERE Name = 'Chris';

Dan

SELECT * FROM Employees WHERE Name LIKE 'Chris';

Akan mengembalikan hasil yang sama, meskipun menggunakan LIKE umumnya akan lebih lama karena kecocokan polanya. Namun,

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

Dan

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

Akan mengembalikan hasil yang berbeda, di mana menggunakan "=" menghasilkan hanya hasil dengan "Chris%" dikembalikan dan operator LIKE akan mengembalikan apa pun yang dimulai dengan "Chris".

Semoga itu bisa membantu. Beberapa info bagus dapat ditemukan di sini .

achinda99
sumber
108
Saya mendapat kesan bahwa OP tahu kapan harus menggunakan LIKE dan kapan harus menggunakan =, dia hanya bertanya-tanya apakah ada perbedaan kinerja ketika tidak ada wildcard. Jawaban ini secara singkat menyentuh ini tetapi saya merasa bahwa 95% dari jawaban ini tidak benar-benar relevan.
Penjahat Programmer
1
Sangat benar. Saya tidak yakin apakah pertanyaannya sama ketika saya menjawabnya. Jika ya, saya melewatkan bagian yang menanyakan kinerja. Terima kasih atas pengamatannya.
achinda99
9
Jawaban ini mengerikan. LIKE dan '=' adalah operator yang benar-benar berbeda, tetapi kebetulan berperilaku serupa di beberapa subset kecil kasus. Demi keturunan, silakan baca sisa balasan di sini, atau setidaknya google untuk "mysql like" sebelum Anda melakukan ini ke memori.
Mark E. Haase
3
Di sisi lain, jawaban ini menjawab pertanyaan yang saya miliki dan cari di Google. Terkadang sama baiknya jika jawaban menjawab judul pertanyaan, seperti konten.
CorayThan
Pikiran yang baik untuk diingat adalah ketika Anda menggunakan char dan varchar2. Jika Anda membandingkan char dengan char. Sebelum membandingkan database, pertama-tama konversikan panjang 'variabel' pertama ke yang sama dari yang kedua. Jika Anda membandingkan char dan varchar2, basis data tidak akan melakukan apa-apa. docs.oracle.com/cd/A64702_01/doc/server.805/a58236/c_char.htm
xild
18

Ini adalah salinan / rekatkan jawaban saya yang lain untuk pertanyaan kinerja SQL 'like' vs '=' :

Contoh pribadi menggunakan mysql 5.5: Saya memiliki gabungan dalam antara 2 tabel, satu dari 3 juta baris dan satu dari 10 ribu baris.

Saat menggunakan sejenis pada indeks seperti di bawah ini (tidak ada wildcard), butuh sekitar 30 detik:

where login like '12345678'

menggunakan 'jelaskan' saya dapatkan:

masukkan deskripsi gambar di sini

Saat menggunakan '=' pada permintaan yang sama, butuh sekitar 0,1 detik:

where login ='12345678'

Menggunakan 'jelaskan' saya dapatkan:

masukkan deskripsi gambar di sini

Seperti yang Anda lihat, like pencarian indeks yang dibatalkan sepenuhnya, jadi kueri membutuhkan waktu 300 kali lebih banyak.

Aris
sumber
17

LIKEdan =berbeda. LIKEadalah apa yang akan Anda gunakan dalam permintaan pencarian. Ini juga memungkinkan wildcard seperti _(karakter wildcard sederhana) dan% (wildcard multi-karakter).

= harus digunakan jika Anda ingin kecocokan yang tepat dan itu akan lebih cepat.

Situs ini menjelaskan LIKE

WalterJ89
sumber
11

Satu perbedaan - terlepas dari kemungkinan untuk menggunakan wildcard dengan LIKE - ada di spasi tambahan: Operator = mengabaikan spasi tambahan, tetapi LIKE tidak.

ISW
sumber
4
Meskipun ini berlaku untuk MySQL dan MS SQL, ini bukan untuk PostgreSQL.
Bruno
10

Tergantung pada sistem basis data.

Umumnya tanpa karakter khusus, ya, = dan LIKE sama.

Namun, beberapa sistem database mungkin memperlakukan pengaturan collation secara berbeda dengan operator yang berbeda.

Sebagai contoh, dalam perbandingan MySQL dengan = pada string selalu case-insensitive secara default, jadi LIKE tanpa karakter khusus adalah sama. Pada beberapa LIKE RDBMS lainnya adalah case-insensitive sementara = tidak.

ʞɔıu
sumber
Apakah ada sesuatu seperti ikhtisar untuk keanehan ini?
Gumbo
9

Untuk contoh ini kita anggap remeh bahwa varcharcol tidak mengandung ''dan tidak memiliki sel kosong di kolom ini

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

Yang pertama menghasilkan 0 baris output sedangkan yang kedua menunjukkan seluruh daftar. = adalah kasus yang benar-benar cocok sementara suka bertindak seperti filter. jika filter tidak memiliki kriteria, setiap data valid.

suka - berdasarkan fungsinya bekerja sedikit lebih lambat dan dimaksudkan untuk digunakan dengan varchar dan data serupa.

Arnab
sumber
6

Jika Anda mencari yang sama persis, Anda bisa menggunakan keduanya, = dan LIKE.

Menggunakan "=" sedikit lebih cepat dalam hal ini (mencari kecocokan yang tepat) - Anda dapat memeriksanya sendiri dengan memiliki kueri yang sama dua kali dalam SQL Server Management Studio, sekali menggunakan "=", sekali menggunakan "LIKE", dan lalu gunakan "Permintaan" / "Sertakan rencana eksekusi aktual".

Jalankan dua pertanyaan dan Anda akan melihat hasil Anda dua kali, ditambah dua rencana eksekusi yang sebenarnya. Dalam kasus saya, mereka dibagi 50% vs 50%, tetapi "=" rencana eksekusi memiliki "perkiraan biaya subtree" yang lebih kecil (ditampilkan ketika Anda mengarahkan kursor ke kotak "SELECT" paling kiri) - tetapi sekali lagi, itu benar-benar bukan perbedaan besar.

Tetapi ketika Anda mulai mencari dengan wildcard dalam ekspresi LIKE Anda, kinerja pencarian akan meredup. Cari "LIKE Mill%" masih bisa cukup cepat - SQL Server dapat menggunakan indeks pada kolom itu, jika ada. Mencari "LIKE% ekspresi%" sangat lambat, karena satu-satunya cara SQL Server dapat memuaskan pencarian ini adalah dengan melakukan pemindaian tabel penuh. Jadi berhati-hatilah dengan LIKE Anda!

Marc

marc_s
sumber
-1 karena tidak, itu tidak selalu sedikit lebih cepat. Jika kolom diindeks menggunakan% mystring% adalah beberapa perintah yang besarnya lebih lambat. Memang setiap standar kode yang bernilai garam mereka akan memiliki pedoman yang ketat tentang kapan dan kapan tidak menggunakan seperti pada yang lebih besar dari database mouse micky.
Cruachan
1
Saya tidak pernah mengatakan itu akan menjadi sedikit lebih lambat untuk semua kasus - saya mengatakan itu akan menjadi sedikit lebih lambat jika Anda mencari kecocokan EXACT. Tentu saja, mencari dengan SEPERTI dan menggunakan wildcard, terutama pada awal dan akhir item pencarian Anda, JAUH lebih lambat, tidak diragukan lagi.
marc_s
Dan ya, saya setuju - orang harus memiliki pedoman yang jelas kapan harus menggunakan LIKE atau tidak (hanya ketika Anda PERLU mencari dengan wildcard). Tapi sekali lagi - dalam teori, tidak ada perbedaan antara teori dan praktik, tetapi dalam praktik .......
marc_s
6

Menggunakan = menghindari wildcard dan konflik karakter khusus dalam string ketika Anda membangun kueri saat run time.

Ini membuat hidup programmer lebih mudah dengan tidak harus melarikan diri dari semua karakter wildcard khusus yang mungkin tergelincir dalam klausa LIKE dan tidak menghasilkan hasil yang diinginkan. Lagipula, = adalah skenario use case 99%, akan sulit untuk melarikan diri setiap saat.

memutar mata pada '90 -an

Saya juga menduga itu sedikit lebih lambat, tapi saya ragu itu penting jika tidak ada wildcard dalam polanya.

Coincoin
sumber
6

Untuk menjawab pertanyaan awal tentang kinerja, ia turun ke pemanfaatan indeks . Ketika pemindaian tabel sederhana terjadi, "LIKE" dan "=" identik . Ketika indeks terlibat, itu tergantung pada bagaimana klausa LIKE terbentuk. Lebih khusus lagi, apa lokasi wildcard (s)?


Pertimbangkan yang berikut ini:

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

Mungkin juga ada perbedaan yang dapat diabaikan dalam pembuatan rencana kueri saat menggunakan "=" vs "LIKE".

Laramie
sumber
4

Selain wildcard, perbedaan antara =AND LIKEakan bergantung pada jenis SQL server dan pada tipe kolom.

Ambil contoh ini:

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 '
  • Menggunakan MS SQL Server 2012 , spasi tambahan akan diabaikan dalam perbandingan, kecuali dengan LIKEsaat tipe kolom VARCHAR.

  • Menggunakan MySQL 5.5 , spasi tambahan akan diabaikan =, tetapi tidak untukLIKE , baik dengan CHARdan VARCHAR.

  • Menggunakan PostgreSQL 9.1 , spasi signifikan dengan keduanya =dan LIKEmenggunakanVARCHAR , tetapi tidak dengan CHAR(lihat dokumentasi ).

    Perilaku dengan LIKEjuga berbeda denganCHAR .

    Menggunakan data yang sama seperti di atas, menggunakan eksplisit CASTpada nama kolom juga membuat perbedaan :

    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)

    Ini hanya mengembalikan baris untuk "CAST baik" dan "CAST col".

Bruno
sumber
2

Kata kunci LIKE tidak diragukan lagi dilengkapi dengan "label harga kinerja" yang terlampir. Yang mengatakan, jika Anda memiliki bidang input yang berpotensi memasukkan karakter wild card untuk digunakan dalam permintaan Anda, saya akan merekomendasikan menggunakan LIKE hanya jika input berisi salah satu wild card. Kalau tidak, gunakan standar yang sama dengan perbandingan.

Salam Hormat...

Josh Stodola
sumber
1

Benar-benar turun ke apa yang Anda ingin lakukan query. Jika Anda bermaksud pasangan yang tepat maka gunakan =. Jika Anda bermaksud pertandingan fuzzier, maka gunakan LIKE. Mengatakan maksud Anda biasanya merupakan kebijakan yang baik dengan kode.

tidak
sumber
1

Di Oracle, 'suka' tanpa wildcard akan mengembalikan hasil yang sama dengan 'sama', tetapi bisa memerlukan pemrosesan tambahan. Menurut Tom Kyte , Oracle akan memperlakukan 'like' tanpa wildcard sebagai 'equals' saat menggunakan literal, tetapi tidak ketika menggunakan variabel bind.

Chris B
sumber
0

=dan LIKEtidak sama;

  1. = cocok dengan string yang tepat
  2. LIKE cocok dengan string yang mungkin berisi wildcard (%)
baretta
sumber
2
Jawaban Tidak Memadai
Ini dapat digunakan tanpa wildcard. Pertanyaannya menanyakan perbedaan untuk kasus yang sama.
M-Razavi