Saya bertanya-tanya apakah ada pilihan "terbaik" untuk pengumpulan di MySQL untuk situs web umum di mana Anda tidak 100% yakin tentang apa yang akan dimasukkan? Saya mengerti bahwa semua penyandian harus sama, seperti MySQL, Apache, HTML dan apa pun di dalam PHP.
Di masa lalu saya telah menetapkan PHP ke output di "UTF-8", tetapi susunan mana yang cocok dengan ini di MySQL? Aku berpikir itu salah satu UTF-8 yang, tapi aku telah menggunakan utf8_unicode_ci
, utf8_general_ci
dan utf8_bin
sebelumnya.
Jawaban:
Perbedaan utama adalah akurasi penyortiran (saat membandingkan karakter dalam bahasa) dan kinerja. Satu-satunya yang istimewa adalah utf8_bin yang untuk membandingkan karakter dalam format biner.
utf8_general_ci
agak lebih cepat daripadautf8_unicode_ci
, tetapi kurang akurat (untuk menyortir). The bahasa tertentu utf8 encoding (sepertiutf8_swedish_ci
) mengandung aturan bahasa tambahan yang membuat mereka yang paling akurat untuk memilah untuk bahasa mereka. Sebagian besar waktu saya gunakanutf8_unicode_ci
(saya lebih suka akurasi daripada peningkatan kinerja kecil), kecuali saya punya alasan yang baik untuk memilih bahasa tertentu.Anda dapat membaca lebih lanjut tentang set karakter unicode tertentu pada manual MySQL - http://dev.mysql.com/doc/refman/5.0/id/charset-unicode-sets.html
sumber
utf8_unicode_*
utf8mb4
danutf8mb4_unicode_520_ci
. Ini memberi Anda sisa bahasa Cina, ditambah peningkatan pemeriksaan.Sebenarnya, Anda mungkin ingin menggunakan
utf8_unicode_ci
atauutf8_general_ci
.utf8_general_ci
memilah dengan menghilangkan semua aksen dan memilah seolah-olah itu adalah ASCIIutf8_unicode_ci
menggunakan urutan pengurutan Unicode, sehingga mengurutkan dengan benar dalam lebih banyak bahasaNamun, jika Anda hanya menggunakan ini untuk menyimpan teks bahasa Inggris, ini tidak akan berbeda.
sumber
Berhati-hatilah dengan masalah ini yang dapat terjadi saat menggunakan
utf8_general_ci
.MySQL tidak akan membedakan beberapa karakter dalam pernyataan pilih, jika susunan
utf8_general_ci
digunakan. Ini dapat menyebabkan bug yang sangat jahat - terutama misalnya, di mana nama pengguna terlibat. Bergantung pada implementasi yang menggunakan tabel database, masalah ini dapat memungkinkan pengguna jahat untuk membuat nama pengguna yang cocok dengan akun administrator.Masalah ini memunculkan dirinya sendiri paling tidak di versi 5.x awal - Saya tidak yakin apakah perilaku ini berubah nanti.
Saya bukan DBA, tetapi untuk menghindari masalah ini, saya selalu memilih yang
utf8-bin
tidak peka terhadap huruf besar-kecil.Script di bawah ini menjelaskan masalah dengan contoh.
sumber
'value'
dan'valUe'
. Inti dari sebuah susunan adalah bahwa ia menyediakan aturan untuk (antara lain) ketika dua string dianggap sama satu sama lain.Cara terbaik adalah menggunakan set karakter
utf8mb4
dengan collationutf8mb4_unicode_ci
.Set karakter
utf8
,, hanya mendukung sejumlah kecil poin kode UTF-8, sekitar 6% dari karakter yang mungkin.utf8
hanya mendukung Basic Multilingual Plane (BMP). Ada 16 pesawat lainnya. Setiap pesawat berisi 65.536 karakter.utf8mb4
mendukung semua 17 pesawat.MySQL akan memotong karakter UTF-8 4 byte yang menghasilkan data rusak.
Set
utf8mb4
karakter diperkenalkan di MySQL 5.5.3 pada 2010-03-24.Beberapa perubahan yang diperlukan untuk menggunakan set karakter baru tidak sepele:
ROW_FORMAT=DYNAMIC
CATATAN: Beralih ke
Barracuda
dariAntelope
, mungkin perlu memulai ulang layanan MySQL lebih dari sekali.innodb_file_format_max
tidak berubah sampai setelah layanan MySQL telah restart untuk:innodb_file_format = barracuda
.MySQL menggunakan
Antelope
format file InnoDB lama .Barracuda
mendukung format baris dinamis, yang akan Anda perlukan jika Anda tidak ingin menemukan kesalahan SQL untuk membuat indeks dan kunci setelah Anda beralih ke charset:utf8mb4
Skenario berikut telah diuji pada MySQL 5.6.17: Secara default, MySQL dikonfigurasi seperti ini:
Hentikan layanan MySQL Anda dan tambahkan opsi ke my.cnf yang ada:
Contoh pernyataan SQL CREATE:
INDEX contact_idx (contact)
jikaROW_FORMAT=DYNAMIC
dihapus dari pernyataan CREATE.CATATAN: Mengubah indeks untuk membatasi ke 128 karakter pertama pada
contact
menghilangkan persyaratan untuk menggunakan Barracuda denganROW_FORMAT=DYNAMIC
Juga perhatikan: ketika dikatakan ukuran field adalah
VARCHAR(128)
, itu bukan 128 byte. Anda dapat menggunakan karakter 128, 4 byte atau 128, 1 byte.INSERT
Pernyataan ini harus berisi karakter 'kotoran' 4 byte di baris 2:Anda dapat melihat jumlah ruang yang digunakan oleh
last
kolom:Di adaptor database Anda, Anda mungkin ingin mengatur charset dan collation untuk koneksi Anda:
Dalam PHP, ini akan ditetapkan untuk:
\PDO::MYSQL_ATTR_INIT_COMMAND
Referensi:
sumber
utf8mb4_unicode_520_ci
lebih baik. Di masa depan, akan adautf8mb4_unicode_800_ci
(atau sesuatu seperti itu), karena MySQL mengejar standar Unicode.Koleksi mempengaruhi bagaimana data diurutkan dan bagaimana string dibandingkan satu sama lain. Itu berarti Anda harus menggunakan susunan yang sebagian besar pengguna harapkan.
Contoh dari dokumentasi unicode charset :
Jadi - itu tergantung pada basis pengguna yang Anda harapkan dan pada seberapa banyak Anda membutuhkan penyortiran yang benar . Untuk basis pengguna bahasa Inggris,
utf8_general_ci
cukup, untuk bahasa lain, seperti Swedia, koleksi khusus telah dibuat.sumber
Pada dasarnya, itu tergantung pada bagaimana Anda memikirkan string.
Saya selalu menggunakan utf8_bin karena masalah yang disorot oleh Guus. Menurut pendapat saya, sejauh menyangkut database, string masih hanya string. String adalah sejumlah karakter UTF-8. Karakter memiliki representasi biner jadi mengapa perlu mengetahui bahasa yang Anda gunakan? Biasanya, orang akan membangun basis data untuk sistem dengan ruang lingkup untuk situs multibahasa. Ini adalah inti dari penggunaan UTF-8 sebagai set karakter. Saya agak murni tetapi saya pikir risiko bug jauh lebih besar daripada sedikit keuntungan yang Anda dapatkan pada pengindeksan. Setiap aturan terkait bahasa harus dilakukan pada tingkat yang jauh lebih tinggi daripada DBMS.
Dalam buku-buku saya, "nilai" seharusnya tidak dalam sejuta tahun sama dengan "valΓΊe".
Jika saya ingin menyimpan bidang teks dan melakukan pencarian kasus yang tidak sensitif, saya akan menggunakan fungsi string MYSQL dengan fungsi PHP seperti RENDAH () dan fungsi php strtolower ().
sumber
Untuk informasi tekstual UTF-8, Anda harus menggunakan
utf8_general_ci
karena ...utf8_bin
: bandingkan string dengan nilai biner dari setiap karakter dalam stringutf8_general_ci
: bandingkan string menggunakan aturan bahasa umum dan menggunakan perbandingan case-insensitivealias itu akan membuat pencarian dan pengindeksan data lebih cepat / lebih efisien / lebih bermanfaat.
sumber
Jawaban yang diterima cukup jelas menyarankan menggunakan utf8_unicode_ci, dan sementara untuk proyek-proyek baru yang hebat, saya ingin menceritakan pengalaman saya yang bertentangan baru-baru ini kalau-kalau itu menghemat waktu.
Karena utf8_general_ci adalah collation default untuk Unicode di MySQL, jika Anda ingin menggunakan utf8_unicode_ci maka Anda harus menentukannya di banyak tempat.
Sebagai contoh, semua koneksi klien tidak hanya memiliki charset default (masuk akal bagi saya) tetapi juga collation default (yaitu collation akan selalu default ke utf8_general_ci untuk unicode).
Kemungkinan, jika Anda menggunakan utf8_unicode_ci untuk bidang Anda, skrip Anda yang terhubung ke basis data harus diperbarui untuk menyebutkan susunan yang diinginkan secara eksplisit - jika tidak, kueri yang menggunakan string teks dapat gagal ketika koneksi Anda menggunakan susunan default.
Hasilnya adalah ketika mengonversi sistem yang ada dengan ukuran berapa pun ke Unicode / utf8, Anda mungkin terpaksa menggunakan utf8_general_ci karena cara MySQL menangani default.
sumber
Untuk kasus yang disoroti oleh Guus, saya akan sangat menyarankan menggunakan utf8_unicode_cs (sensitif huruf, pencocokan ketat, memesan dengan benar untuk sebagian besar) alih-alih utf8_bin (pencocokan ketat, pemesanan salah).
Jika bidang ini dimaksudkan untuk dicari, dan bukan dicocokkan dengan pengguna, maka gunakan utf8_general_ci atau utf8_unicode_ci. Keduanya tidak peka terhadap huruf besar-kecil, satu akan kalah cocok ('Γ' sama dengan 's', dan bukan 'ss'). Ada juga versi khusus bahasa, seperti utf8_german_ci di mana pencocokan kehilangan lebih cocok untuk bahasa yang ditentukan.
[Sunting - hampir 6 tahun kemudian]
Saya tidak lagi merekomendasikan set karakter "utf8" di MySQL, dan sebaliknya merekomendasikan set karakter "utf8mb4". Mereka cocok hampir seluruhnya, tetapi memungkinkan untuk sedikit (banyak) karakter unicode lebih banyak.
Secara realistis, MySQL seharusnya memperbarui set karakter "utf8" dan collations masing-masing agar sesuai dengan spesifikasi "utf8", tetapi sebaliknya, set karakter terpisah dan collations masing-masing agar tidak memengaruhi penunjukan penyimpanan bagi mereka yang sudah menggunakan set karakter "utf8" mereka yang tidak lengkap. .
sumber
utf8_unicode_cs
tidak ada Satu-satunya utf8 case-sensitive adalahutf8_bin
. Masalahutf8_bin
menyortir tidak benar. Lihat: stackoverflow.com/questions/15218077/...Saya menemukan diagram susunan ini bermanfaat. http://collation-charts.org/mysql60/ . Saya tidak yakin mana yang digunakan utf8_general_ci.
Sebagai contoh di sini adalah bagan untuk utf8_swedish_ci. Ini menunjukkan karakter mana yang ditafsirkan sebagai sama. http://collation-charts.org/mysql60/mysql604.utf8_swedish_ci.html
sumber
Dalam file unggah basis data Anda, tambahkan baris followin sebelum baris apa pun:
Dan masalah Anda harus diselesaikan.
sumber
SET NAMES
kueri secara langsung tidak membuat klien tahu tentang penyandian dan dapat merusak fitur tertentu seperti pernyataan yang disiapkan dengan cara yang sangat halus.