Apa susunan terbaik untuk digunakan untuk MySQL dengan PHP? [Tutup]


731

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_cidan utf8_binsebelumnya.


35
Catatan: MySQL "utf8" tidak layak UTF-8 (tidak ada dukungan untuk karakter Unicode 4+ byte seperti πŒ†), namun "utf8mb4" adalah. Dengan utf8, sebuah bidang akan dipotong pada sisipan yang dimulai dengan karakter Unicode pertama yang tidak didukung. mathiasbynens.be/notes/mysql-utf8mb4
basic6

6
Saya ingin tahu apakah kita akan membutuhkan 5 byte untuk semua emoji itu ... sigh
Álvaro GonzÑlez

1
Pertanyaan terkait: stackoverflow.com/questions/38228335/... "Kolaborasi MySQL mana yang cocok dengan perbandingan string PHP?"
William Entriken

Untuk tinjauan umum dari opsi waras: monolune.com/mysql-utf8-charsets-and-collations-explained
Flux

Jawaban:


618

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_ciagak lebih cepat daripada utf8_unicode_ci, tetapi kurang akurat (untuk menyortir). The bahasa tertentu utf8 encoding (seperti utf8_swedish_ci) mengandung aturan bahasa tambahan yang membuat mereka yang paling akurat untuk memilah untuk bahasa mereka. Sebagian besar waktu saya gunakan utf8_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


4
peningkatan kinerja kecil? apa kau yakin tentang ini ? publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp?topic=/... Kolaborasi yang Anda pilih dapat berdampak signifikan terhadap kinerja kueri dalam database.
Adam Ramadhan

62
Ini untuk DB2 bukan MySQL. Juga, tidak ada angka atau tolok ukur yang konkret sehingga Anda hanya mendasarkannya pada pendapat penulis.
Eran Galperin

3
Perhatikan bahwa jika Anda ingin menggunakan fungsi, ada bug di MySQL (versi yang paling baru didistribusikan) di mana fungsi selalu mengembalikan string menggunakan utf8_general_ci, menyebabkan masalah jika Anda menggunakan susunan
El Yobo

1
Dari pengalaman saya dengan berbagai lokal yang selalu saya gunakanutf8_unicode_*
Shiplu Mokaddim

11
Pembaruan: Untuk versi yang lebih baru, rekomendasikan utf8mb4dan utf8mb4_unicode_520_ci. Ini memberi Anda sisa bahasa Cina, ditambah peningkatan pemeriksaan.
Rick James

129

Sebenarnya, Anda mungkin ingin menggunakan utf8_unicode_ciatau utf8_general_ci.

  • utf8_general_ci memilah dengan menghilangkan semua aksen dan memilah seolah-olah itu adalah ASCII
  • utf8_unicode_ci menggunakan urutan pengurutan Unicode, sehingga mengurutkan dengan benar dalam lebih banyak bahasa

Namun, jika Anda hanya menggunakan ini untuk menyimpan teks bahasa Inggris, ini tidak akan berbeda.


1
Saya suka penjelasan Anda! Bagus Tapi saya perlu pemahaman yang lebih baik tentang mengapa urutan unicode adalah cara yang lebih baik untuk mengurutkan dengan benar daripada menghilangkan aksen.
desain weia

14
@Adam Itu benar-benar tergantung pada audiens target Anda. Penyortiran adalah masalah rumit untuk dilokalkan dengan benar. Misalnya dalam bahasa Norwegia huruf Γ† Ø Γ… adalah 3 terakhir dari alfabet. Dengan utf8_general_ci, Ø dan Γ… dikonversikan ke O dan A, yang menempatkan mereka pada posisi yang benar-benar salah ketika diurutkan (saya tidak yakin bagaimana Γ† ditangani, karena itu adalah ligatur, bukan karakter beraksen). Urutan pengurutan ini berbeda di hampir semua bahasa, misalnya Norwegia dan Swedia memiliki urutan berbeda (dan huruf yang sedikit berbeda yang dianggap sama): Γ† Ø Γ… diurutkan Γ… Γ† Ø (huruf sebenarnya adalah Γ… Γ„ Γ–). Unicode memperbaiki ini.
Vegard Larsen

Jadi apa yang saya katakan pada dasarnya, adalah bahwa Anda mungkin harus menggunakan jenis bahasa tertentu jika Anda bisa, tetapi dalam kebanyakan kasus itu tidak layak, jadi pergi untuk penyortiran umum Unicode. Ini masih akan aneh dalam beberapa bahasa, tetapi lebih benar daripada ASCII.
Vegard Larsen

3
@Manatax - dengan semua koleksi utf8_, data disimpan sebagai utf8. Kolasi hanya tentang karakter apa yang dianggap sama, dan bagaimana mereka dipesan.
frymaster

2
@frymaster - tidak benar, seperti: mathiasbynens.be/notes/mysql-utf8mb4 " Utf8 MySQL hanya memungkinkan Anda untuk menyimpan 5,88% dari semua kemungkinan titik kode Unicode"
data

120

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_cidigunakan. 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-bintidak peka terhadap huruf besar-kecil.

Script di bawah ini menjelaskan masalah dengan contoh.

-- first, create a sandbox to play in
CREATE DATABASE `sandbox`;
use `sandbox`;

-- next, make sure that your client connection is of the same 
-- character/collate type as the one we're going to test next:
charset utf8 collate utf8_general_ci

-- now, create the table and fill it with values
CREATE TABLE `test` (`key` VARCHAR(16), `value` VARCHAR(16) )
    CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO `test` VALUES ('Key ONE', 'value'), ('Key TWO', 'valΓΊe');

-- (verify)
SELECT * FROM `test`;

-- now, expose the problem/bug:
SELECT * FROM test WHERE `value` = 'value';

--
-- Note that we get BOTH keys here! MySQLs UTF8 collates that are 
-- case insensitive (ending with _ci) do not distinguish between 
-- both values!
--
-- collate 'utf8_bin' doesn't have this problem, as I'll show next:
--

-- first, reset the client connection charset/collate type
charset utf8 collate utf8_bin

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Note that we get just one key now, as you'd expect.
--
-- This problem appears to be specific to utf8. Next, I'll try to 
-- do the same with the 'latin1' charset:
--

-- first, reset the client connection charset/collate type
charset latin1 collate latin1_general_ci

-- next, convert the values that we've previously inserted
-- in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET latin1 COLLATE latin1_general_ci;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Again, only one key is returned (expected). This shows 
-- that the problem with utf8/utf8_generic_ci isn't present 
-- in latin1/latin1_general_ci
--
-- To complete the example, I'll check with the binary collate
-- of latin1 as well:

-- first, reset the client connection charset/collate type
charset latin1 collate latin1_bin

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET latin1 COLLATE latin1_bin;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Again, only one key is returned (expected).
--
-- Finally, I'll re-introduce the problem in the exact same 
-- way (for any sceptics out there):

-- first, reset the client connection charset/collate type
charset utf8 collate utf8_generic_ci

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

-- now, re-check for the problem/bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Two keys.
--

DROP DATABASE sandbox;

36
-1: Ini pasti diatasi dengan menerapkan kunci unik ke kolom yang relevan. Anda akan melihat perilaku yang sama jika kedua nilai tersebut adalah 'value'dan 'valUe'. Inti dari sebuah susunan adalah bahwa ia menyediakan aturan untuk (antara lain) ketika dua string dianggap sama satu sama lain.
Hammerite

13
Persis itulah masalah yang saya coba gambarkan - susunan membuat dua hal menjadi sama, padahal sebenarnya tidak dimaksudkan sama sama sekali (dan dengan demikian, kendala unik persis kebalikan dari apa yang ingin Anda capai)
Guus

18
Tapi Anda menggambarkannya sebagai "masalah" dan mengarah ke "bug" ketika perilaku itu persis apa yang ingin dicapai oleh sebuah pemeriksaan. Deskripsi Anda benar, tetapi hanya sebanyak kesalahan pada bagian DBA untuk memilih susunan yang tidak pantas.
Hammerite

32
Masalahnya adalah, ketika Anda memasukkan dua nama pengguna yang dianggap sama dengan susunan, itu tidak akan diizinkan jika Anda menetapkan nama pengguna kolom menjadi unik, yang tentu saja harus Anda lakukan!
Siswa Hogwarts

12
Saya mengangkat jawaban ini dan juga komentar @ Hammerite, karena keduanya dikombinasikan membantu saya mencapai pemahaman tentang pengumpulan.
Nacht - Reinstate Monica

86

Cara terbaik adalah menggunakan set karakter utf8mb4dengan collation utf8mb4_unicode_ci.

Set karakter utf8,, hanya mendukung sejumlah kecil poin kode UTF-8, sekitar 6% dari karakter yang mungkin. utf8hanya mendukung Basic Multilingual Plane (BMP). Ada 16 pesawat lainnya. Setiap pesawat berisi 65.536 karakter. utf8mb4mendukung semua 17 pesawat.

MySQL akan memotong karakter UTF-8 4 byte yang menghasilkan data rusak.

Set utf8mb4karakter diperkenalkan di MySQL 5.5.3 pada 2010-03-24.

Beberapa perubahan yang diperlukan untuk menggunakan set karakter baru tidak sepele:

  • Perubahan mungkin perlu dilakukan di adaptor basis data aplikasi Anda.
  • Perubahan perlu dilakukan pada my.cnf, termasuk mengatur set karakter, susunan dan beralih innodb_file_format ke Barracuda
  • Pernyataan SQL CREATE mungkin perlu mencakup: ROW_FORMAT=DYNAMIC
    • DYNAMIC diperlukan untuk indeks pada VARCHAR (192) dan lebih besar.

CATATAN: Beralih ke Barracudadari Antelope, mungkin perlu memulai ulang layanan MySQL lebih dari sekali. innodb_file_format_maxtidak berubah sampai setelah layanan MySQL telah restart untuk: innodb_file_format = barracuda.

MySQL menggunakan Antelopeformat file InnoDB lama . Barracudamendukung 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

  • # 1709 - Ukuran kolom indeks terlalu besar. Ukuran kolom maksimum adalah 767 byte.
  • # 1071 - Kunci yang ditentukan terlalu panjang; panjang kunci maks adalah 767 byte

Skenario berikut telah diuji pada MySQL 5.6.17: Secara default, MySQL dikonfigurasi seperti ini:

SHOW VARIABLES;

innodb_large_prefix = OFF
innodb_file_format = Antelope

Hentikan layanan MySQL Anda dan tambahkan opsi ke my.cnf yang ada:

[client]
default-character-set= utf8mb4

[mysqld]
explicit_defaults_for_timestamp = true
innodb_large_prefix = true
innodb_file_format = barracuda
innodb_file_format_max = barracuda
innodb_file_per_table = true

# Character collation
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci

Contoh pernyataan SQL CREATE:

CREATE TABLE Contacts (
 id INT AUTO_INCREMENT NOT NULL,
 ownerId INT DEFAULT NULL,
 created timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 contact VARCHAR(640) NOT NULL,
 prefix VARCHAR(128) NOT NULL,
 first VARCHAR(128) NOT NULL,
 middle VARCHAR(128) NOT NULL,
 last VARCHAR(128) NOT NULL,
 suffix VARCHAR(128) NOT NULL,
 notes MEDIUMTEXT NOT NULL,
 INDEX IDX_CA367725E05EFD25 (ownerId),
 INDEX created (created),
 INDEX modified_idx (modified),
 INDEX contact_idx (contact),
 PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT=DYNAMIC;
  • Anda dapat melihat kesalahan # 1709 dihasilkan INDEX contact_idx (contact)jika ROW_FORMAT=DYNAMICdihapus dari pernyataan CREATE.

CATATAN: Mengubah indeks untuk membatasi ke 128 karakter pertama pada contactmenghilangkan persyaratan untuk menggunakan Barracuda denganROW_FORMAT=DYNAMIC

INDEX contact_idx (contact(128)),

Juga perhatikan: ketika dikatakan ukuran field adalah VARCHAR(128), itu bukan 128 byte. Anda dapat menggunakan karakter 128, 4 byte atau 128, 1 byte.

INSERTPernyataan ini harus berisi karakter 'kotoran' 4 byte di baris 2:

INSERT INTO `Contacts` (`id`, `ownerId`, `created`, `modified`, `contact`, `prefix`, `first`, `middle`, `last`, `suffix`, `notes`) VALUES
(1, NULL, '0000-00-00 00:00:00', '2014-08-25 03:00:36', '1234567890', '12345678901234567890', '1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678', '', ''),
(2, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', '', ''),
(3, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', '123πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', '', '');

Anda dapat melihat jumlah ruang yang digunakan oleh lastkolom:

mysql> SELECT BIT_LENGTH(`last`), CHAR_LENGTH(`last`) FROM `Contacts`;
+--------------------+---------------------+
| BIT_LENGTH(`last`) | CHAR_LENGTH(`last`) |
+--------------------+---------------------+
|               1024 |                 128 | -- All characters are ASCII
|               4096 |                 128 | -- All characters are 4 bytes
|               4024 |                 128 | -- 3 characters are ASCII, 125 are 4 bytes
+--------------------+---------------------+

Di adaptor database Anda, Anda mungkin ingin mengatur charset dan collation untuk koneksi Anda:

SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'

Dalam PHP, ini akan ditetapkan untuk: \PDO::MYSQL_ATTR_INIT_COMMAND

Referensi:



Informasi lebih lanjut tentang Wikipedia: Pesawat Unicode
Jeremy Postlethwaite

6
utf8mb4_unicode_ci benar-benar harus direkomendasikan untuk proyek baru di 2015.
Trevor Gehman

7
Perbarui ... utf8mb4_unicode_520_cilebih baik. Di masa depan, akan ada utf8mb4_unicode_800_ci(atau sesuatu seperti itu), karena MySQL mengejar standar Unicode.
Rick James

46

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 :

utf8_general_cijuga memuaskan untuk Jerman dan Perancis, kecuali bahwa 'ß' sama dengan 's', dan bukan 'ss'. Jika ini dapat diterima untuk aplikasi Anda, maka Anda harus menggunakannya utf8_general_cikarena lebih cepat. Kalau tidak, gunakan utf8_unicode_cikarena lebih akurat.

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_cicukup, untuk bahasa lain, seperti Swedia, koleksi khusus telah dibuat.


1
saya menggunakan utf8_general_ci dan butuh beberapa detik sambil menyortir dan armscii_general_ci melakukannya dengan sangat cepat. Mengapa ini terjadi? Satu pertanyaan lagi, Menurut Anda, apa collation yang digunakan oleh situs jejaring sosial

22

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 ().


9
Jika perbandingan string biner adalah perbandingan yang Anda inginkan, maka tentu saja Anda harus menggunakan pemeriksaan biner; tetapi untuk mengabaikan pemeriksaan alternatif sebagai "risiko bug" atau sekadar untuk memudahkan pengindeksan menunjukkan bahwa Anda tidak sepenuhnya memahami titik pemeriksaan.
Hammerite

13

Untuk informasi tekstual UTF-8, Anda harus menggunakan utf8_general_cikarena ...

  • utf8_bin: bandingkan string dengan nilai biner dari setiap karakter dalam string

  • utf8_general_ci: bandingkan string menggunakan aturan bahasa umum dan menggunakan perbandingan case-insensitive

alias itu akan membuat pencarian dan pengindeksan data lebih cepat / lebih efisien / lebih bermanfaat.


12

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.


8

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. .


5
FYI: utf8_unicode_cstidak ada Satu-satunya utf8 case-sensitive adalah utf8_bin. Masalah utf8_binmenyortir tidak benar. Lihat: stackoverflow.com/questions/15218077/...
Costa

1
Terima kasih telah memperbarui!
Prometheus


2

Dalam file unggah basis data Anda, tambahkan baris followin sebelum baris apa pun:

SET NAMES utf8;

Dan masalah Anda harus diselesaikan.


2
Baca pertanyaan: Di masa lalu saya telah menetapkan PHP ke output di "UTF-8", tetapi susunan mana yang cocok dengan ini di MySQL? Saya pikir itu salah satu yang UTF-8, tapi saya telah menggunakan utf8_unicode_ci, utf8_general_ci, dan utf8_bin sebelumnya.
Jitesh Sojitra

5
Jawaban ini tidak ada hubungannya dengan pertanyaan. Selain itu, mengeluarkan SET NAMESkueri secara langsung tidak membuat klien tahu tentang penyandian dan dapat merusak fitur tertentu seperti pernyataan yang disiapkan dengan cara yang sangat halus.
Álvaro GonzÑlez
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.