Utf8_general_ci ve utf8_unicode_ci arasındaki fark nedir?


1063

Arasında utf8_general_cive utf8_unicode_ci, performans açısından herhangi bir fark vardır?



6
İsterseniz utf8[mb4]_unicode_ci, siz olabilir gibi utf8[mb4]_unicode_520_cidaha fazla.
Rick James

8
Bu konuda nasıl hissettiğimi bilmiyorum - en son Unicode standardını takip etmek için uygulamalarını düzeltmek yerine, eski sürümü varsayılan olarak tutarlar ve insanların şimdi uygun olanı kullanmak için "520" eklemeleri gerekir. İleri ve geri uyumlu değildir, çünkü "520" sürümünü eski MySQL sürümlerinde kullanamazsınız. Neden mevcut harmanlamalarını güncelleyemediler? Gerçekten "mb4" ile aynı. Hangi kod, varsayılanı korumayı haklı çıkarmak için eski, sınırlı / eski davranışa gerçekten bağlıydı?
thomasrutter

7
Yine de 8.0'ın varsayılan değeri daha iyidir utf8mb4_0900_ai_ci.
Rick James

Yanıtlar:


1591

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 utf8mb4yerine kullanmak zorundasınız utf8. Kafa karıştırıcı bir şekilde, utf8erken 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_cihı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_cioverutf8mb4_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_cisı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_cibunları 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_cibü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_ciCPU 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_cidoğ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_cimuhtemelen 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, cibü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) binve 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 unicodeveya generalbelirli 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 unicodeve generaliki 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. unicodeUnicode 4.0 kurallarını kullanan unutmayın . MySQL'in son sürümleri, unicode_520Unicode 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, utf8mb4elbette dahili olarak kullanılan karakter kodlamasıdır. Bu cevapta sadece Unicode tabanlı kodlamalar hakkında konuşuyorum.


218
@KahWeeTeng Asla, asla kullanmamalısınız 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.
tchrist

7
Bunu okuduktan sonra aynı zamanda utf8_unicode_ci eşitlik karşılaştırması amacıyla aynı harmanlama ağırlığına sahip karakterleri eşit olarak değerlendireceğini keşfettim. Bu, "か" == "が"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
Mat Schaffer

4
@DanHorvat Kendinizi MySQL'in eski, daha sınırlı Unicode alt kümesiyle sınırlamanın tek pratik nedeni, MySQL'in daha eksiksiz utf8mb4'ü desteklemeyen eski bir sürümüne sahip olmanızdır. 5.5.3, 5 yaşın üzerindedir. Ben Plesk Farklı MySQL tarifede çalışır takdir, ancak çoğu dağıtımlar artık MySQL 5.5 üzerinde ve Plesk 11.x yapar onun bileşenlerini güncellemek durumunda destek MySQL 5.5.
thomasrutter

22
Daha yeni, daha standart şikayet şikayet varyantını kullanmanın kötü bir uygulama olduğunu kabul etmiyorum ve bence insanlara kötü geliştiricilere böyle bir şey demenin iltihaplı olduğunu düşünüyorum. Ayrıca cevabımın durduğu gibi " MySQL'in yeni sürümlerinde utf8 yerine utf8mb4 kullanıyorum" dediğini vurgulamak isteyebilirsiniz.
thomasrutter

24
@DanHorvat utf8mb4olduğunu sadece doğru seçim . İle utf8Eğ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 utf8ve geriye dönük uyumluluğu bozmamak için artık gerçek UTF8'e başvurmak zorundalar utf8mb4.
Stijn de Witt

162

Kullanmak utf8_general_ciile 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, SELECTile LIKEve sıralama ( SELECTile 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_ciharmanlama kullanılır, ancak elbette testler sırasında hem utf8_general_cive hem de kullandım utf8_unicode_ci.

Her saklı yordamı her harmanlama için 5 kez (5 kez utf8_general_cive 5 kez utf8_unicode_ci) çağırdım ve sonra ortalama değerleri hesapladım.

Sonuçlarım:

benchmark_simple_select()

  • ile utf8_general_ci: 9.957 ms
  • ile utf8_unicode_ci: 10.271 ms

Bu kıyaslamada kullanmak % utf8_unicode_ci3,2'den daha yavaştır utf8_general_ci.

benchmark_select_like()

  • ile utf8_general_ci: 11.441 ms
  • ile utf8_unicode_ci: 12.811 ms

Bu kıyaslamada utf8_unicode_cikullanımı utf8_general_ci% 12'den daha yavaştır .

benchmark_order_by()

  • ile utf8_general_ci: 11.944 ms
  • ile utf8_unicode_ci: 12.887 ms

Bu kıyaslamada utf8_unicode_cikullanımı utf8_general_ci% 7,9 daha yavaştır .


16
Güzel bir referans, paylaştığınız için teşekkürler. Çok benzer rakamlar alıyorum (Windows'ta MySQL v5.6.12):% 10,% 4,% 8. Katılıyorum: performans kazancı utf8_general_cikullanmaya değmeyecek kadar az.
RandomSeed

10
1) Ancak bu karşılaştırma ölçütü tanım gereği iki harmanlama için benzer sonuçlar üretmemeli midir? Yani 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.
Halil Özgür

2
@ HalilÖzgür - amacınız kısmen yanlış. Ben ASCII dışında olmak için kod noktası değeri hakkında değil (hangi general_ci doğru ele alacağı), ama "Uml ea ute" veya böyle bazı incelikleri yazılı olarak yazılan muamele gibi belirli özellikleri hakkında sanırım .
Tomasz Gandor

38

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.


1
Teşekkürler. bu benim izlenimimdi. Ben performans hit alacak :)
onassar

7
Doğruluğu umursamıyorsanız, herhangi bir algoritmayı sonsuz hızlı yapmak önemsizdir. Sadece kullanın utf8_unicode_cive diğerinin yokmuş gibi davranın.
tchrist

1
@tchrist ama doğruluk ve hız arasındaki belirli bir dengeyi önemsiyorsanız, utf8_general_cisizin için olabilir
Shelvacu

@tchrist Asla bir oyun programcısı olmayın;)
Stijn de Witt

1
@onassar - MySQL 8.0 , tüm harmanlamaların performansını önemli ölçüde artırdığını iddia ediyor .
Rick James

9

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.


18
“Biraz daha az doğru” diye bir şey yoktur. Doğruluk boolean bir özelliktir; derece değiştiricileri kabul etmez. Sadece kullanın utf8_unicode_cive buggy kırık sürümü yokmuş gibi davranın.
tchrist

2
Ben collation_connection ayarını almak için 5.6.15 alma sorunları vardı ve 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci' gibi SET satırında geçmek zorunda olduğu ortaya çıkıyor. Kredi çözüm için Mathias Bynens'e gidiyor, işte onun çok faydalı kılavuzu: mathiasbynens.be/notes/mysql-utf8mb4
Steve Hibbert

4
@tchrist Doğruluk söyleme sorunu booleandır, mutlak doğruluk dayanmayan durumları dikkate almaz. Temel noktanız geçersiz değil ya da general_ci'nin yararlarını benimsemeye çalışıyorum, ancak doğruluk hakkındaki genel ifadeniz kolayca kanıtlanamıyor. Mesleğimde bunu günlük olarak yapıyorum. Komedi bir yana, Stuart'ın burada iyi bir noktası var .
Anthony

5
Coğrafi konum veya oyun geliştirme ile her zaman performansla doğruluk ticaretini yapıyoruz. Ve tabii doğruluğu gerçek arasındaki sayıdır 0ve 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
Stijn de Witt

4
TL; DR : Lütfen doğru sonucu 1/3
yazdırın

7

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.


1
Her ikisi de şimdi modası geçmiş - daha fazla bilgi için kabul edilen cevaba bakınız
thomasrutter

OK, thank you @thomasrutter
simhumileco

6

Bazı detaylar (PL)

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ı Lve öncesidir M. Bu kodlamadan hiç kimse daha iyi veya daha kötü değildir - ihtiyaçlarınıza bağlıdır.


1

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_cisizde var i != ı, ama içinde utf8mb4_general_civar ı=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_ciama ile yan yana konumlandırılması durumunda utf8mb4_unicode_cibunun olacağını değil satır dönmek!

Öte yandan buna sahibiz a=ªve ß=ssiçinde utf8mb4_unicode_cidurum 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 .


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.