Arasında utf8_general_ci
ve utf8_unicode_ci
, performans açısından herhangi bir fark vardır?
utf8[mb4]_unicode_ci
, siz olabilir gibi utf8[mb4]_unicode_520_ci
daha fazla.
utf8mb4_0900_ai_ci
.
Arasında utf8_general_ci
ve utf8_unicode_ci
, performans açısından herhangi bir fark vardır?
utf8[mb4]_unicode_ci
, siz olabilir gibi utf8[mb4]_unicode_520_ci
daha fazla.
utf8mb4_0900_ai_ci
.
Yanıtlar:
Bu iki harmanlama UTF-8 karakter kodlaması içindir. Farklılıklar metnin nasıl sıralandığı ve karşılaştırıldığıdır.
Not: MySQL'de kullanmak utf8mb4
yerine kullanmak zorundasınız utf8
. Kafa karıştırıcı bir şekilde, utf8
erken MySQL sürümlerinden gelen ve sadece geriye dönük uyumluluk için kalan hatalı bir UTF-8 uygulamasıdır. Sabit versiyona isim verilmiştir utf8mb4
.
Not: MySQL'in daha yeni sürümleri utf8mb4_0900_ai_ci
, Unicode 9.0 tabanlı eşdeğer kurallar gibi adlar altında bulunan ve eşdeğer _general
varyant içermeyen güncellenmiş Unicode sıralama kurallarına sahiptir . Bunu şimdi okuyan insanlar muhtemelen ya _unicode
da yerine bu yeni harmanlamalardan birini kullanmalıdır_general
. Aşağıda yazılanların çoğu, daha yeni harmanlamalardan birini kullanabiliyorsanız artık fazla ilgi çekmiyor.
Temel farklılıklar
utf8mb4_unicode_ci
çok çeşitli dillerde doğru şekilde sıralanan evrensel sıralama ve karşılaştırma için resmi Unicode kurallarına dayanmaktadır.
utf8mb4_general_ci
hızı iyileştirmek için tasarlanan birçok kısa yol alırken aynı zamanda yapmayı da amaçlayan basitleştirilmiş bir sıralama kuralları kümesidir. Unicode kurallarına uymaz ve belirli dillerde veya karakterlerin kullanılması gibi bazı durumlarda istenmeyen sıralama veya karşılaştırma ile sonuçlanır.
Modern sunucularda, bu performans artışı göz ardı edilemez. Sunucuların günümüz bilgisayarlarının CPU performansının küçük bir kısmına sahip olduğu bir zamanda tasarlandı.
Faydaları utf8mb4_unicode_ci
overutf8mb4_general_ci
utf8mb4_unicode_ci
, sıralama ve karşılaştırma için Unicode kurallarını kullanan çok çeşitli dillerde ve çok sayıda özel karakter kullanırken doğru sıralama için oldukça karmaşık bir algoritma kullanır. Bu kuralların dile özgü kuralları dikkate alması gerekir; herkes karakterlerini 'alfabetik sıra' olarak adlandırdığımız şekilde sıralamaz.
Latince (yani "Avrupa") dillere gelince, Unicode sıralama ve MySQL'deki basitleştirilmiş utf8mb4_general_ci
sıralama arasında çok fazla fark yoktur , ancak hala birkaç fark vardır:
Örnekler için Unicode Harmanlama sıralar "ss" gibi "ß" ve normalde isteyeyim bu karakterleri kullanan kişiler olarak "OE" gibi "Î", oysa utf8mb4_general_ci
(sırasıyla muhtemelen "s" ve "e" gibi) tek karakter olarak türlü onları .
Bazı Unicode karakterler cahil olarak tanımlanır, yani sıralama düzenine dahil edilmemeleri ve karşılaştırma yerine bir sonraki karaktere geçmeleri gerekir. utf8mb4_unicode_ci
bunları düzgün bir şekilde işler.
Asya dilleri veya farklı alfabelere sahip diller gibi latin olmayan dillerde, Unicode sıralama ve basitleştirilmiş sıralama arasında çok daha fazla fark olabilir utf8mb4_general_ci
. Öğesinin uygunluğu utf8mb4_general_ci
büyük ölçüde kullanılan dile bağlı olacaktır. Bazı diller için oldukça yetersiz olacaktır.
Ne kullanmalısın?
utf8mb4_general_ci
CPU hızının performans farkının önemli olacağı kadar düşük olduğu noktayı geride bıraktığımız için artık kesinlikle kullanmak için neredeyse hiçbir neden yok. Veritabanınız neredeyse bundan başka darboğazlarla sınırlı olacaktır.
Geçmişte, utf8mb4_general_ci
doğru sıralamanın performans maliyetini haklı çıkaracak kadar önemli olmadığı durumlar dışında bazı insanlar kullanmayı önerdi . Bugün, bu performans maliyeti ortadan kalktı ve geliştiriciler uluslararasılaşmayı daha ciddiye alıyorlar.
Hız sizin için doğruluktan daha önemliyse, herhangi bir sıralama yapamayabileceğiniz konusunda bir argüman var. Doğru olması gerekmiyorsa bir algoritmayı daha hızlı hale getirmek önemsizdir. Yani, utf8mb4_general_ci
muhtemelen hız nedenleri için gerekli olmayan ve muhtemelen doğruluk nedenleri için uygun olmayan bir uzlaşmadır.
Ekleyeceğim diğer bir şey, uygulamanızın sadece İngilizce dilini desteklediğini bilseniz bile, yine de doğru şekilde sıralamanın önemli olduğu diğer dillerde kullanılan karakterleri içerebilen insanların adlarıyla ilgilenmesi gerekebilir. . Unicode kurallarını her şey için kullanmak, çok akıllı Unicode kullanıcılarının sıralamanın düzgün çalışması için çok çalıştığı için gönül rahatlığı sağlar.
Parçaların anlamı
İlk olarak, ci
büyük / küçük harfe duyarlı olmayan sıralama ve karşılaştırma içindir. Bu, metinsel veriler için uygun olduğu ve durumun önemli olmadığı anlamına gelir. Diğer harmanlama türleri, büyük / küçük harflerin cs
önemli olduğu metin verileri için (büyük / küçük harfe duyarlıdır) bin
ve kodlamanın eşleşmesi gereken yerlerde, gerçekten kodlanmış ikili veriler (örneğin, Base64). Büyük / küçük harfe duyarlı sıralama bazı garip sonuçlara yol açar ve büyük / küçük harfe duyarlı karşılaştırma yalnızca harf durumunda farklılık gösteren yinelenen değerlere neden olabilir, bu nedenle büyük / küçük harf duyarlı harmanlamalar metin verileri için lehine düşer - büyük / küçük harf kullanımı sizin için önemliyse, aksi takdirde cahil noktalama işaretleri ve benzerleri de muhtemelen önemlidir ve ikili bir harmanlama daha uygun olabilir.
Sonra unicode
veya general
belirli sıralama ve karşılaştırma kurallarına atıfta bulunur - özellikle metnin normalleştirme veya karşılaştırma şekli. Orada utf8mb4 karakter kodlama için kurallar çok farklı setleri ile vardır unicode
ve general
iki varlık olduğunu iyi olası tüm dillerde çalışmalarına girişimi ziyade belirli bir. Bu iki kural kümesi arasındaki farklar bu cevabın konusudur. unicode
Unicode 4.0 kurallarını kullanan unutmayın . MySQL'in son sürümleri, unicode_520
Unicode 5.2'deki kuralları kullanarak ve 0900
("unicode_" bölümünü bırakarak) Unicode 9.0'daki kuralları kullanarak kural kümelerini ekler .
Ve son olarak, utf8mb4
elbette dahili olarak kullanılan karakter kodlamasıdır. Bu cevapta sadece Unicode tabanlı kodlamalar hakkında konuşuyorum.
utf8_general_ci
: bu işe yaramaz. Elli yıl önceki ASCII yaşama gücünün kötü eski günlerine bir geri dönüş. Unicode büyük / küçük harfe duyarlı olmayan eşleme, UCD'den gelen kılıf haritası olmadan gerçekleştirilemez. Örneğin, “Σίσυφος” içinde üç farklı sigma vardır; ya da “TSCHüẞ” küçük harfinin “tschüβ”, fakat “tschüβ” büyük harfinin “TSCHÜSS” olması. Haklı olabilirsin ya da hızlı olabilirsin. Bu nedenle kullanmalısınız utf8_unicode_ci
, çünkü doğrulukla ilgilenmiyorsanız, o zaman sonsuz hızlı yapmak önemsizdir.
"か" == "が"
veya olduğu durumlarda yol açar "ǽ" == "æ"
. Bunu sıralamak mantıklıdır, ancak eşitlikler yoluyla seçerken veya benzersiz endekslerle uğraşırken şaşırtıcı olabilir - bugs.mysql.com/bug.php?id=16526
utf8mb4
olduğunu sadece doğru seçim . İle utf8
Eğer UTF8 bazı MySQL okunur, 3 baytlık varyantı sıkışmış sadece MySQL (ve mariadb) ne yapacağını biliyoruz. Dünyanın geri kalanı karakter başına 4 bayt içerebilen UTF8 kullanıyor . MySQL geliştiricileri homebrew kodlamasını yanlış adlandırdılar utf8
ve geriye dönük uyumluluğu bozmamak için artık gerçek UTF8'e başvurmak zorundalar utf8mb4
.
Kullanmak utf8_general_ci
ile performans arasındaki farkın ne olduğunu bilmek istedim utf8_unicode_ci
, ancak internette listelenen bir kıyaslama ölçütü bulamadım, bu yüzden kendim için kıyaslama ölçütleri oluşturmaya karar verdim.
500.000 satırlı çok basit bir tablo oluşturdum:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Sonra bu saklı yordamı çalıştırarak rastgele verilerle doldurdu:
CREATE PROCEDURE randomizer()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE random CHAR(20) ;
theloop: loop
SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
INSERT INTO test VALUES (i+1, random);
SET i=i+1;
IF i = 500000 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END
Sonra basit SELECT
, SELECT
ile LIKE
ve sıralama ( SELECT
ile ORDER BY
) karşılaştırmak için aşağıdaki saklı yordamlar oluşturdum :
CREATE PROCEDURE benchmark_simple_select()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description = 'test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_select_like()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description LIKE '%test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_order_by()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
SET i = i + 1;
IF i = 10 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
Yukarıdaki saklı yordamlarda utf8_general_ci
harmanlama kullanılır, ancak elbette testler sırasında hem utf8_general_ci
ve hem de kullandım utf8_unicode_ci
.
Her saklı yordamı her harmanlama için 5 kez (5 kez utf8_general_ci
ve 5 kez utf8_unicode_ci
) çağırdım ve sonra ortalama değerleri hesapladım.
Sonuçlarım:
benchmark_simple_select()
utf8_general_ci
: 9.957 ms utf8_unicode_ci
: 10.271 ms Bu kıyaslamada kullanmak % utf8_unicode_ci
3,2'den daha yavaştır utf8_general_ci
.
benchmark_select_like()
utf8_general_ci
: 11.441 ms utf8_unicode_ci
: 12.811 ms Bu kıyaslamada utf8_unicode_ci
kullanımı utf8_general_ci
% 12'den daha yavaştır .
benchmark_order_by()
utf8_general_ci
: 11.944 ms utf8_unicode_ci
: 12.887 ms Bu kıyaslamada utf8_unicode_ci
kullanımı utf8_general_ci
% 7,9 daha yavaştır .
utf8_general_ci
kullanmaya değmeyecek kadar az.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
sadece ASCII üretir ve harmanlama algoritmaları tarafından işlenecek Unicode karakterleri yoktur. 2) Description = 'test' COLLATE ...
ve Description LIKE 'test%' COLLATE ...
çalışma zamanında yalnızca tek bir dize ("test") işliyorlar, değil mi? 3) Gerçek uygulamalarda, sıralamada kullanılan sütunlar muhtemelen dizine eklenir ve gerçek ASCII olmayan metne sahip farklı harmanlamalarda dizinleme hızı farklı olabilir.
Bu yazı çok güzel anlatıyor.
Kısacası: utf8_unicode_ci, Unicode standartlarında tanımlandığı gibi Unicode Harmanlama Algoritmasını kullanırken, utf8_general_ci "daha az doğru" sıralama sonuçlarıyla sonuçlanan daha basit bir sıralama düzenidir.
utf8_unicode_ci
ve diğerinin yokmuş gibi davranın.
utf8_general_ci
sizin için olabilir
MySQL el kitabı, Unicode Karakter Kümeleri bölümüne bakın:
Herhangi bir Unicode karakter kümesi için, _general_ci harmanlama kullanılarak gerçekleştirilen işlemler _unicode_ci harmanlama işleminden daha hızlıdır. Örneğin, utf8_general_ci harmanlama karşılaştırmaları utf8_unicode_ci karşılaştırmasından daha hızlıdır, ancak biraz daha az doğrudur. Bunun nedeni utf8_unicode_ci'nin genişletme gibi eşlemeleri desteklemesi; diğer bir deyişle, bir karakter diğer karakterlerin kombinasyonlarıyla eşit olarak karşılaştırıldığında. Örneğin, Almanca ve diğer bazı dillerde “ß” “ss” e eşittir. utf8_unicode_ci kasılmaları ve cahil karakterleri de destekler. utf8_general_ci, genişletmeleri, kasılmaları veya cahil karakterleri desteklemeyen eski bir harmanlamadır. Karakterler arasında sadece bire bir karşılaştırma yapabilir.
Özetlemek gerekirse, utf_general_ci , tüm standardı uygulaması gereken utf_unicode_ci'ye göre daha küçük ve daha az doğru (standarda göre) karşılaştırmalar kullanır . General_ci kümesi daha hızlı olacaktır çünkü yapacak daha az hesaplama vardır.
utf8_unicode_ci
ve buggy kırık sürümü yokmuş gibi davranın.
0
ve 1
, bir bool. :) Sınırlayıcı bir kutuda coğrafi noktaları seçmek EG, nokta ile referans noktası arasındaki mesafeyi hesaplamak ve filtrelemek kadar iyi olmayan 'yakındaki noktaların' bir tahminidir. Ancak her ikisi de bir yaklaşımdır ve aslında, tam doğruluk çoğunlukla elde edilemez. Bkz sahil paradoks ve IEEE 754
1/3
Kısaca:
Daha iyi sıralama düzenine ihtiyacınız varsa - kullanın utf8_unicode_ci
(bu tercih edilen yöntemdir),
ancak performansla tamamen ilgileniyorsanız - kullanın utf8_general_ci
, ancak biraz modası geçmiş olduğunu bilin.
Performans açısından farklılıklar çok azdır.
Okuduğumuz gibi burada ( Peter Gulutzan ) cilası "L" harfi karşılaştıran / sıralama üzerinde farklılık (inme ile L - html esc: Ł
) (küçük harfle: "L" - html esc: ł
) - biz varsayımı vardır:
utf8_polish_ci Ł greater than L and less than M
utf8_unicode_ci Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci Ł greater than Z
Lehçe dilinde harf harf Ł
sonrası L
ve öncesidir M
. Bu kodlamadan hiç kimse daha iyi veya daha kötü değildir - ihtiyaçlarınıza bağlıdır.
Sıralama ve karakter eşleşmesinin iki büyük farkı vardır:
Sıralama :
utf8mb4_general_ci
tüm aksanları kaldırır ve yanlış sıralama sonuçları oluşturabilecek şekilde tek tek sıralar.utf8mb4_unicode_ci
doğru sıralar.Karakter Eşleme
Karakterleri farklı şekilde eşleştiriyorlar.
Örneğin, utf8mb4_unicode_ci
sizde var i != ı
, ama içinde utf8mb4_general_ci
var ı=i
.
Örneğin, bir satırınız olduğunu düşünün name="Yılmaz"
. Sonra
select id from users where name='Yilmaz';
kolokasyon ise satır dönecekti utf8mb4_general_ci
ama ile yan yana konumlandırılması durumunda utf8mb4_unicode_ci
bunun olacağını değil satır dönmek!
Öte yandan buna sahibiz a=ª
ve ß=ss
içinde utf8mb4_unicode_ci
durum böyle değil utf8mb4_general_ci
. Öyleyse bir satırınız olduğunu düşünün name="ªßi"
, o zaman
select id from users where name='assi';
kolokasyon ise satır dönecekti utf8mb4_unicode_ci
, ama olur değil sıralama olarak ayarlanırsa, bir satır döndürür utf8mb4_general_ci
.
Her bir kollokasyon için tam eşleşme listesi burada bulunabilir .
Bu yayına göre, utf8mb4_unicode_ci yerine utf8mb4_general_ci kullanılırken MySQL 5.7 üzerinde oldukça büyük bir performans avantajı var: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mySQL performanslı /