UTF-8: Umum? Tempat sampah? Unicode?

279

Saya mencoba mencari tahu susunan apa yang harus saya gunakan untuk berbagai jenis data. 100% dari konten yang akan saya simpan dikirimkan oleh pengguna.

Pemahaman saya adalah bahwa saya harus menggunakan UTF-8 General CI (Case-Insensitive) daripada UTF-8 Binary. Namun, saya tidak dapat menemukan perbedaan yang jelas antara UTF-8 General CI dan UTF-8 Unicode CI.

  1. Haruskah saya menyimpan konten yang dikirimkan pengguna dalam kolom UTF-8 Umum atau UTF-8 Unicode CI?
  2. Tipe data apa yang akan diterapkan oleh UTF-8 Binary?
Dolph
sumber
16
Catatan samping tetapi alih-alih utf8, gunakan utf8mb4sebagai ganti untuk dukungan penuh UTF-8. Mengomentari di sini karena jawaban atas pertanyaan populer ini tidak membahas ini. mathiasbynens.be/notes/mysql-utf8mb4
Steven R. Loomis
Jika Anda ingin melipat case, tetapi sensitivitas aksen, silakan ajukan permintaan di bugs.mysql.com .
Rick James
Atau klik "Mempengaruhi Saya" di bugs.mysql.com/bug.php?id=58797 dan tambahkan komentar.
Rick James

Jawaban:

299

Secara umum, utf8_general_ci lebih cepat dari utf8_unicode_ci , tetapi kurang tepat.

Inilah perbedaannya:

Untuk setiap set karakter Unicode, operasi yang dilakukan menggunakan collation _general_ci lebih cepat daripada yang untuk collation _unicode_ci . Sebagai contoh, perbandingan untuk collation utf8_general_ci lebih cepat, tetapi sedikit kurang benar, dibandingkan dengan perbandingan utf8_unicode_ci. Alasannya adalah utf8_unicode_ci mendukung pemetaan seperti ekspansi; yaitu, ketika satu karakter membandingkan sama dengan kombinasi karakter lain. Misalnya, dalam bahasa Jerman dan beberapa bahasa lainnya "ß" sama dengan "ss". utf8_unicode_ci juga mendukung karakter kontraksi dan diabaikan. utf8_general_ci adalah kumpulan warisan yang tidak mendukung ekspansi, kontraksi, atau karakter yang dapat diabaikan. Itu hanya dapat membuat perbandingan satu-ke-satu antara karakter.

Dikutip dari: http://dev.mysql.com/doc/refman/5.0/id/charset-unicode-sets.html

Untuk penjelasan lebih rinci, silakan baca posting berikut dari forum MySQL: http://forums.mysql.com/read.php?103,187048,188748

Adapun utf8_bin: Baik utf8_general_ci dan utf8_unicode_ci melakukan perbandingan case-insensitive. Dalam konstrast , utf8_bin adalah case-sensitive (di antara perbedaan lainnya), karena membandingkan nilai biner dari karakter.

Sagi
sumber
2
Saya pikir jika Anda tidak memiliki alasan yang baik untuk menggunakan _unicode_ci, maka gunakan _general_ci.
Sagi
4
Ini tidak benar-benar menjawab pertanyaan secara mendalam. Apa perbedaan antara susunan ini sebenarnya?
Pekka
4
Anda benar, perbedaan yang pasti tidak disediakan di sini demi kesederhanaan. Saya telah menambahkan tautan ke pos dengan perbedaan yang tepat .
Sagi
NB show collation;memungkinkan Anda untuk melihat susunan default untuk setiap set karakter. 5.1 ditampilkan utf8_general_cisebagai default untuk utf8.
David Carboni
9
Apakah ada sumber daya yang akan lebih mendalam dalam perbedaan kecepatan aktual antara kedua pemeriksaan? Apakah kita berbicara tentang penurunan 0,1% dalam kinerja atau penurunan 10%?
Emphram Stavanger
90

Anda juga harus menyadari fakta, bahwa dengan utf8_general_ci saat menggunakan bidang varchar sebagai indeks utama atau unik memasukkan 2 nilai seperti 'a' dan 'á' akan memberikan kesalahan kunci duplikat.

Alex Hepp
sumber
3
Terima kasih, ini berguna untuk menghindari nama pengguna yang serupa (mis. Jika "jose" ada, saya tidak ingin orang lain membuat pengguna "josé") NB: ini juga berlaku untuk sebagian besar koleksi utf8 (kecuali utf8_bin). Yang paling pasti / paling aman / terlengkap adalahutf8_unicode_ci
Costa
2
Saya menggunakan utf8_bin di mana saya ingin jose dan jose dibedakan dalam indeks. Misalnya, kolom yang mencatat operasi pencarian / ganti, di mana pengguna mungkin telah memutuskan untuk mencari josé, dan menggantinya dengan jose. (Saya sedang menulis program spreadsheet)
Buttle Butkus
33
  • utf8_binmembandingkan bit secara membabi buta. Tidak ada case lipat, tidak ada aksen stripping.
  • utf8_general_cimembandingkan satu byte dengan satu byte. Itu kasus lipat dan aksen stripping, tapi tidak ada perbandingan 2 karakter: ijtidak sama ijdalam susunan ini.
  • utf8_*_ciadalah seperangkat aturan khusus bahasa, tetapi sebaliknya suka unicode_ci. Beberapa kasus khusus: Ç, Č, ch,ll
  • utf8_unicode_cimengikuti standar Unicode lama untuk perbandingan. ij= ij, tapi ae! =æ
  • utf8_unicode_520_cimengikuti standar Unicode yang lebih baru. ae=æ

Lihat bagan collation untuk perincian tentang apa yang sama dengan apa di berbagai collations utf8.

utf8, seperti yang didefinisikan oleh MySQL terbatas pada kode utf8 1- hingga 3 byte. Ini meninggalkan Emoji dan beberapa orang Cina. Jadi Anda harus benar-benar beralih ke utf8mb4jika Anda ingin pergi jauh ke luar Eropa.

Poin di atas berlaku untuk utf8mb4 , setelah perubahan ejaan yang sesuai. Maju, utf8mb4dan utf8mb4_unicode_520_cilebih disukai.

  • utf16 dan utf32 adalah varian di utf8; hampir tidak ada gunanya bagi mereka.
  • ucs2 lebih dekat ke "Unicode" daripada "utf8"; hampir tidak ada gunanya untuk itu.
Rick James
sumber
1
Re "stay tuned": 8.0 collations menunjukkan bagaimana beragam karakter, diftong, dll., Dibandingkan dalam 8.0 collations utf8mb4; utf8 sebagian besar sama.
Rick James
Dan 8,0 collations dihitung secara signifikan lebih cepat dari 5.x.
Rick James
alangkah baiknya jika halaman itu mencantumkan utf8mb4_bin di bagian atas. Saya tahu itu tidak cocok dengan karakter sama sekali, tapi itu bagus untuk pemula.
Henk Poley
6

Sungguh, saya menguji nilai tabungan seperti 'é' dan 'e' di kolom dengan unik indeks dan mereka menyebabkan kesalahan duplikat pada 'utf8_unicode_ci' dan 'utf8_general_ci'. Anda dapat menyimpannya hanya di kolom susun 'utf8_bin'.

Dan dokumen mysql (di http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html ) menyarankan ke dalam contoh-contohnya set susunan 'utf8_general_ci'.

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
vitalii
sumber
1
Saya melakukan tes cepat pada ini, dan tampaknya akurat. Kedua susunan berperilaku sama ketika datang ke kunci unik pada kolom dan nilai dengan tildes dan sejenisnya.
MirroredFate
@ MirroredFate OK, saya harus menambahkan di sana bahwa kolom harus memiliki indeks unik untuk menyebabkan kesalahan ini. Itu tersirat dalam jawaban saya.
vitalii
3

Jawaban yang diterima sudah usang.

Jika Anda menggunakan MySQL 5.5.3+, gunakan utf8mb4_unicode_cialih-alih utf8_unicode_ciuntuk memastikan karakter yang diketik oleh pengguna Anda tidak akan memberi Anda kesalahan.

utf8mb4mendukung emoji misalnya, sedangkan utf8mungkin memberi Anda ratusan bug terkait penyandian seperti:

Incorrect string value: ‘\xF0\x9F\x98\x81…’ for column ‘data’ at row 1

Marwann
sumber
Jawaban ini (dengan benar) membahas masalah dengan penyandian Emoji (dan beberapa bahasa Cina). Tapi Pertanyaannya sepertinya difokuskan pada Collation. utf8mb4_unicode_cimemperlakukan (saya pikir) semua Emoji sebagai sama. utf8mb4_unicode_520_cimemberikan pemesanan ke Emoji.
Rick James