SQL kullanırken =
, WHERE
yerine bir cümle kullanmanın herhangi bir faydası var LIKE
mı?
Herhangi bir özel operatör olmadan LIKE
ve =
aynı, değil mi?
5
için oy kullanıyor . Eşanlamlı olarak sql-like önermenizi rica edebilir miyim ?
SQL kullanırken =
, WHERE
yerine bir cümle kullanmanın herhangi bir faydası var LIKE
mı?
Herhangi bir özel operatör olmadan LIKE
ve =
aynı, değil mi?
5
için oy kullanıyor . Eşanlamlı olarak sql-like önermenizi rica edebilir miyim ?
Yanıtlar:
LIKE
ve =
farklı operatörlerdir. Buradaki yanıtların çoğu, bu operatörler arasındaki tek fark olmayan joker karakter desteğine odaklanıyor!
=
sayı ve karakter dizileri üzerinde çalışan bir karşılaştırma operatörüdür. Dizeleri karşılaştırırken karşılaştırma operatörü tüm dizeleri karşılaştırır .
LIKE
bir karakter karakter karşılaştırır dize işleci .
Konuları karmaşıklaştırmak için, her iki operatör de karşılaştırmanın sonucu üzerinde önemli etkileri olabilecek bir harmanlama kullanır .
Önce bu operatörlerin açıkça farklı sonuçlar ürettikleri bir örnek belirleyelim. MySQL kılavuzundan alıntı yapmama izin ver:
SQL standardına göre LIKE, karakter başına esasına göre eşleştirme gerçekleştirir, böylece = karşılaştırma işlecinden farklı sonuçlar üretebilir:
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 |
+--------------------------------------+
Lütfen MySQL kılavuzunun bu sayfasına Dize Karşılaştırma İşlevleri adı =
verildiğini ve bu konuların tartışılmadığını unutmayın;=
bir dize karşılaştırma işlevi olmadığını unutmayın.
=
Çalışır?SQL Standart § 8.2 açıklamaktadır =
dizeleri karşılaştırır:
İki karakter dizesinin karşılaştırması aşağıdaki gibi belirlenir:
a) X karakterlerindeki uzunluk, Y karakterlerindeki uzunluğa eşit değilse, daha kısa dize, karşılaştırma amacıyla, kendisinin uzun dizenin uzunluğuna uzatılmış bir kopyasıyla etkili bir şekilde değiştirilir. ped karakterinin CS'ye göre seçildiği bir veya daha fazla ped karakterinin sağında birleştirme ile. CS NO PAD özniteliğine sahipse, pad karakteri, X ve Y karakter kümesindeki CS altındaki herhangi bir dizeden daha az harmanlayan herhangi bir karakterden farklı, uygulamaya bağlı bir karakterdir. Aksi takdirde, pad karakteri a şeklindedir.
b) X ve Y karşılaştırmasının sonucu, harmanlama sekansı CS ile verilir.
c) Harmanlama sırasına bağlı olarak, farklı uzunluklarda olsa veya farklı karakter dizileri içeriyor olsalar bile, iki dize eşit olarak karşılaştırılabilir. MAX, MIN, DISTINCT işlemleri, bir gruplama sütununa başvurular ve UNION, EXCEPT ve INTERSECT işleçleri karakter dizelerine başvurduğunda, bu işlemler tarafından bu tür bir eşit değer kümesinden seçilen belirli değer uygulamaya bağlıdır.
(Vurgu eklenmiştir.)
Ne anlama geliyor? Bu, dizeleri karşılaştırırken, =
operatörün mevcut harmanlama etrafında sadece ince bir sargı olduğu anlamına gelir . Harmanlama, dizeleri karşılaştırmak için çeşitli kurallara sahip bir kütüphanedir. İşte MySQL'den ikili bir harmanlama örneği :
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);
}
Bu özel harmanlama bayt byte baytı karşılaştırır (bu yüzden "ikili" olarak adlandırılır - dizelere özel bir anlam vermez). Diğer harmanlamalar daha gelişmiş karşılaştırmalar sağlayabilir.
Örneğin, büyük / küçük harfe duyarlı olmayan karşılaştırmaları destekleyen bir UTF-8 harmanlaması . Kod buraya yapıştırmak için çok uzun, ama bu bağlantıya gidin ve gövdesini okuyun my_strnncollsp_utf8mb4()
. Bu harmanlama bir seferde birden fazla bayt işleyebilir ve çeşitli dönüşümler uygulayabilir (büyük / küçük harf duyarsız karşılaştırma gibi). =
Operatör tamamen harmanlama kaprisleri soyutlanmış bir.
LIKE
Çalışır?SQL Standart § 8.5 açıklamaktadır LIKE
dizeleri karşılaştırır:
<predicate>
M LIKE P
M'nin alt dizelere bölümlenmesi varsa doğrudur:
i) M'nin bir alt dizisi, M'nin 0 veya daha fazla bitişik <karakter gösterimi> s dizisidir ve M'nin her <karakter gösterimi> tam olarak bir alt dizenin bir parçasıdır.
ii) P'nin i-alt alt dizesi belirteci rasgele bir karakter belirleyicisi ise, M'nin i-alt alt dizesi herhangi bir <karakter temsili> dir.
iii) P'nin i-th alt dizesi tanımlayıcısı isteğe bağlı bir dize tanımlayıcısıysa, M'nin i-alt alt dizisi 0 veya daha fazla <karakter temsili> s dizisidir.
iv) P'nin i-th alt dizesi belirleyicisi ne rastgele bir karakter belirleyicisi ne de rastgele bir dize belirleyicisi değilse, M'nin i-alt alt dizesi, <benzer yüklem> öğesinin harmanlama sırasına göre bu alt dize belirtecine eşittir. <boşluk> karakterlerinin M'ye eklenmesi ve bu alt dize belirleyicisiyle aynı uzunlukta olması gerekir.
v) M'nin alt dize sayısı P'nin alt dize belirteçlerinin sayısına eşittir.
(Vurgu eklenmiştir.)
Bu oldukça garip, hadi onu yıkalım. İi ve iii maddeleri sırasıyla joker karakterlere _
ve %
Herhangi P
bir joker karakter içermiyorsa, yalnızca iv. Öğe uygulanır. Bu OP tarafından ortaya çıkarılan bir ilgi durumudur.
Bu durumda, geçerli harmanlamayı kullanarak her bir "alt dizeyi" (tek tek karakterler) M
her bir alt dizeyle P
karşılaştırır.
En alt satır, dizeleri =
karşılaştırırken, tüm dizeyi LIKE
karşılaştırırken bir kerede bir karakter karşılaştırmasıdır. Her iki karşılaştırma da geçerli harmanlamayı kullanır. Bu fark, bu yazıda ilk örnekte görüldüğü gibi, bazı durumlarda farklı sonuçlara yol açmaktadır.
Hangisini kullanmalısın? Kimse size bunu söyleyemez - kullanım durumunuz için doğru olanı kullanmanız gerekir. Karşılaştırma işleçlerini değiştirerek zamanından önce optimize etmeyin.
LIKE
, ancak bu cevap, LIKE
olmadan %
veya _
mevcut olmadan kullanmanın , kullanımla aynı olmadığını açık bir şekilde açıklıyor =
. Cevabınız binlerce oy alsın.
'AbCdEfG'
ve ben de WHERE MyCol = 'abcdefg'
, bayt byte bayt eşdeğeri olmamasına rağmen yine de bu satırı geri alıyorum
set charset latin1;
SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
0 SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
veriyor ve 0 veriyor.
Equals (=) operatörü "karşılaştırma operatörü eşitlik için iki değeri karşılaştırır." Başka bir deyişle, bir SQL deyiminde, denklemin her iki tarafı eşit olmadığı sürece true değerini döndürmez. Örneğin:
SELECT * FROM Store WHERE Quantity = 200;
LIKE işleci, bir dize değerini joker karakter içeren bir desen dizesiyle eşleştirmeye çalışan "bir desen eşleştirme karşılaştırması" uygular. Örneğin:
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
LIKE genellikle sadece dizelerle kullanılır ve eşittir (sanırım) daha hızlıdır. Eşittir işleci joker karakterlere gerçek karakter olarak davranır. Döndürülen sonuçlardaki fark aşağıdaki gibidir:
SELECT * FROM Employees WHERE Name = 'Chris';
Ve
SELECT * FROM Employees WHERE Name LIKE 'Chris';
LIKE kullanmak genellikle bir desen eşleşmesi olarak daha uzun sürer olsa da, aynı sonucu dönecekti. Ancak,
SELECT * FROM Employees WHERE Name = 'Chris%';
Ve
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
"=" Kullanıldığında yalnızca "Chris%" döndürülür ve LIKE operatörü "Chris" ile başlayan her şeyi döndürür.
Umarım yardımcı olur. Bazı iyi bilgileri burada bulabilirsiniz .
Bu, 'vs' = 'performansı gibi SQL sorusu için başka bir cevabımın bir kopyası / yapıştırmasıdır :
MySQL 5.5 kullanarak kişisel bir örnek: 2 tablo, 3 milyon sıradan biri ve 10 bin sıradan biri arasında bir iç birleşim vardı.
Aşağıdaki gibi bir dizinde bir benzeri kullanılırken (joker karakterler yok), yaklaşık 30 saniye sürdü:
where login like '12345678'
'açıkla' kullanarak şunu elde ederim:
Aynı sorguda '=' kullanılırken, yaklaşık 0.1 saniye sürdü:
where login ='12345678'
'Anlat' kullanarak şunu elde ederim:
Gördüğünüz gibi like
, dizin aramasını tamamen iptal etti, bu yüzden sorgu 300 kat daha fazla zaman aldı.
LIKE
ve =
farklı. LIKE
bir arama sorgusunda kullanacağınız şeydir. Ayrıca _
(basit karakter joker karakteri) ve %
(çok karakterli joker karakter) gibi joker karakterlere izin verir .
=
tam eşleşme istiyorsanız kullanılmalıdır ve daha hızlı olacaktır.
Veritabanı sistemine bağlıdır.
Genelde özel karakterler olmadan evet, = ve LIKE aynıdır.
Bununla birlikte, bazı veritabanı sistemleri, harmanlama ayarlarını farklı işleçlerle farklı şekilde ele alabilir.
Örneğin, MySQL'de = on dizeleri ile karşılaştırmalar her zaman varsayılan olarak büyük / küçük harfe duyarlı değildir, bu nedenle özel karakterler içermeyen LIKE aynıdır. Diğer bazı RDBMS'lerin LIKE değeri büyük / küçük harfe duyarlı değildir, ancak = değildir.
Bu örnekte varcharcol'un ''
bu sütuna karşı boş hücre içermediğini ve boş hücre içermediğini kabul ediyoruz
select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''
Birincisi 0 satır çıktısı verirken ikincisi tüm listeyi gösterir. = bir filtre gibi davranırken, kesinlikle eşleşir. filtrenin ölçütleri yoksa, her veri geçerlidir.
gibi - amacı nedeniyle biraz daha yavaş çalışır ve varchar ve benzer verilerle kullanım için tasarlanmıştır.
Tam eşleşme ararsanız, = ve LIKE değerlerini kullanabilirsiniz.
Bu durumda "=" kullanmak biraz daha hızlıdır (tam eşleşme aranıyor) - SQL Server Management Studio'da aynı sorguyu iki kez, bir kez "=" kullanarak, bir kez "LIKE" kullanarak ve ardından "Sorgu" / "Gerçek yürütme planını dahil et" seçeneğini kullanın.
İki sorguyu yürütün; sonuçlarınızı iki kez ve iki gerçek yürütme planını görmelisiniz. Benim durumumda,% 50'ye karşı% 50'ye bölündüler, ancak "=" yürütme planında daha küçük bir "tahmini alt ağaç maliyeti" var (en soldaki "SEÇİM" kutusunun üzerine geldiğinizde görüntülenir) - ancak yine, gerçekten büyük bir fark değil.
Ancak, LIKE ifadenizdeki joker karakterlerle aramaya başladığınızda, arama performansı azalır. "LIKE Mill%" araması oldukça hızlı olabilir - SQL Server, varsa, bu sütunda bir dizin kullanabilir. SQL Server'ın bu aramayı tatmin etmesinin tek yolu tam tablo taraması yapmak olduğundan, "LIKE% expression%" ifadesini aramak son derece yavaştır. Bu yüzden GİBİ'lerinize dikkat edin!
üzüm posası
= Kullanıldığında, sorguyu çalışma zamanında oluşturduğunuzda dizede joker karakterler ve özel karakter çakışmaları önlenir.
Bu, LIKE yan tümcesinde kayabilecek tüm özel joker karakterlerden kaçmak zorunda kalmadan ve amaçlanan sonucu üretmeden programcının hayatını kolaylaştırır. Sonuçta, =% 99 kullanım senaryosu, her seferinde onlardan kaçmak bir acı olur.
90'larda gözlerini deviriyor
Ayrıca biraz daha yavaş olduğundan şüpheliyim, ancak desende joker karakter olmaması önemli.
Performansla ilgili orijinal soruyu ele almak için, endeks kullanımı söz konusudur . Basit bir tablo taraması gerçekleştiğinde, "LIKE" ve "=" aynıdır . Dizinler söz konusu olduğunda , LIKE yantümcesinin nasıl oluştuğuna bağlıdır . Daha spesifik olarak, joker karakterlerin yeri nedir?
Aşağıdakileri göz önünde bulundur:
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" kullanılırken sorgu planının oluşturulmasında da ihmal edilebilir bir fark olabilir.
Joker karakterlerin yanı sıra, =
AND arasındaki fark LIKE
hem SQL sunucusunun türüne hem de sütun türüne bağlı olacaktır.
Bu örneği ele alalım:
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 '
Kullanımı MS SQL Server 2012 , arkada kalan boşluklar hariç, karşılaştırmalı olarak göz ardı edilecektir LIKE
kolon tipi olduğu zaman VARCHAR
.
Kullanma MySQL 5.5 , arkada kalan boşluklar için göz ardı edilecektir =
, ancak için LIKE
, her ikisi de CHAR
ve VARCHAR
.
Kullanma PostgreSQL 9.1 , boşluk hem de önemli olan =
ve LIKE
kullanılarak VARCHAR
, fakat ile CHAR
(bakınız belgeler ).
İle davranışı LIKE
daCHAR
.
Yukarıdaki verilerle aynı verileri kullanmak CAST
, sütun adında bir belirti kullanmak da bir fark yaratır :
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)
Bu yalnızca "CAST hem" ve "CAST col" satırlarını döndürür.
LIKE anahtar kelimesi kuşkusuz bir "performans fiyat etiketi" eklenmiş olarak gelir. Bununla birlikte, sorgunuzda kullanılacak joker karakterleri içerebilecek bir giriş alanınız varsa, yalnızca aşağıdaki durumlarda LIKE kullanmanızı öneririm , girdi joker kartlardan birini içeriyorsa . Aksi takdirde, karşılaştırmaya eşit olan standardı kullanın.
Saygılarımla...
Oracle'da, joker karakter içermeyen bir "like", "eşittir" ile aynı sonucu döndürür, ancak ek işlem gerektirebilir. Tom Kyte'e göre Oracle, değişmez değerleri kullanırken joker karakter içermeyen bir "like" ı "değişmez" olarak ele alacak, ancak bağlama değişkenlerini kullanırken değil.
=
ve LIKE
aynı değil;
=
tam dizeyle eşleşir LIKE
joker karakterler (%) içerebilecek bir dizeyle eşleşir