Antara utf8_general_ci
dan utf8_unicode_ci
, apakah ada perbedaan dalam hal kinerja?
utf8[mb4]_unicode_ci
, Anda mungkin lebih suka utf8[mb4]_unicode_520_ci
.
utf8mb4_0900_ai_ci
.
Antara utf8_general_ci
dan utf8_unicode_ci
, apakah ada perbedaan dalam hal kinerja?
utf8[mb4]_unicode_ci
, Anda mungkin lebih suka utf8[mb4]_unicode_520_ci
.
utf8mb4_0900_ai_ci
.
Jawaban:
Kedua kumpulan ini keduanya untuk pengkodean karakter UTF-8. Perbedaannya terletak pada bagaimana teks diurutkan dan dibandingkan.
Catatan: Di MySQL Anda harus menggunakan utf8mb4
daripada utf8
. Yang membingungkan, utf8
adalah implementasi UTF-8 yang cacat dari versi MySQL awal yang tetap hanya untuk kompatibilitas ke belakang. Versi tetap diberi nama utf8mb4
.
Catatan: Versi MySQL yang lebih baru telah memperbarui aturan penyortiran Unicode, tersedia dengan nama seperti utf8mb4_0900_ai_ci
aturan setara berdasarkan Unicode 9.0 - dan tanpa _general
varian yang setara . Orang yang membaca ini sekarang mungkin harus menggunakan salah satu dari kumpulan yang lebih baru ini, bukan salah satu _unicode
atau _general
. Banyak dari apa yang ditulis di bawah ini tidak menarik lagi jika Anda dapat menggunakan salah satu dari kumpulan yang lebih baru.
Perbedaan utama
utf8mb4_unicode_ci
didasarkan pada aturan Unicode resmi untuk pengurutan dan perbandingan universal, yang mengurutkan secara akurat dalam berbagai bahasa.
utf8mb4_general_ci
adalah seperangkat aturan penyortiran yang disederhanakan yang bertujuan untuk melakukan sebaik mungkin sambil mengambil banyak jalan pintas yang dirancang untuk meningkatkan kecepatan. Itu tidak mengikuti aturan Unicode dan akan menghasilkan penyortiran yang tidak diinginkan atau perbandingan dalam beberapa situasi, seperti ketika menggunakan bahasa atau karakter tertentu.
Pada server modern, peningkatan kinerja ini akan sangat kecil. Itu dirancang pada saat server memiliki sebagian kecil dari kinerja CPU komputer saat ini.
Manfaat utf8mb4_unicode_ci
lebihutf8mb4_general_ci
utf8mb4_unicode_ci
, yang menggunakan aturan Unicode untuk pengurutan dan perbandingan, menggunakan algoritma yang cukup rumit untuk pengurutan yang benar dalam berbagai bahasa dan ketika menggunakan berbagai karakter khusus. Aturan-aturan ini perlu mempertimbangkan konvensi khusus bahasa akun; tidak semua orang mengurutkan karakter mereka dalam apa yang kita sebut 'urutan abjad'.
Sejauh bahasa Latin (yaitu "Eropa"), tidak ada banyak perbedaan antara pengurutan Unicode dan pengurutan yang disederhanakan utf8mb4_general_ci
di MySQL, tetapi masih ada beberapa perbedaan:
Sebagai contoh, pemeriksaan Unicode mengurutkan "ß" seperti "ss", dan "Œ" seperti "OE" seperti yang diinginkan orang yang menggunakan karakter tersebut, sedangkan utf8mb4_general_ci
mengurutkannya sebagai karakter tunggal (mungkin masing-masing seperti huruf "s" dan "e") .
Beberapa karakter Unicode didefinisikan sebagai diabaikan, yang berarti mereka tidak boleh diperhitungkan dalam urutan pengurutan dan perbandingan harus beralih ke karakter berikutnya. utf8mb4_unicode_ci
menangani ini dengan benar.
Dalam bahasa non-latin, seperti bahasa Asia atau bahasa dengan huruf yang berbeda, mungkin ada lebih banyak perbedaan antara pengurutan Unicode dan pengurutan yang disederhanakan utf8mb4_general_ci
. Kesesuaian utf8mb4_general_ci
akan sangat bergantung pada bahasa yang digunakan. Untuk beberapa bahasa, itu akan sangat tidak memadai.
Apa yang harus Anda gunakan?
Hampir tidak ada alasan untuk menggunakannya utf8mb4_general_ci
lagi, karena kami telah meninggalkan titik di mana kecepatan CPU cukup rendah sehingga perbedaan kinerja akan menjadi penting. Basis data Anda hampir pasti akan dibatasi oleh kemacetan lain selain ini.
Di masa lalu, beberapa orang merekomendasikan untuk menggunakan utf8mb4_general_ci
kecuali ketika penyortiran yang akurat akan menjadi cukup penting untuk membenarkan biaya kinerja. Saat ini, biaya kinerja telah hilang sama sekali, dan pengembang memperlakukan internasionalisasi dengan lebih serius.
Ada argumen yang dibuat bahwa jika kecepatan lebih penting bagi Anda daripada akurasi, Anda mungkin juga tidak melakukan penyortiran sama sekali. Itu sepele untuk membuat algoritma lebih cepat jika Anda tidak perlu akurat. Jadi, utf8mb4_general_ci
adalah kompromi yang mungkin tidak diperlukan untuk alasan kecepatan dan mungkin juga tidak cocok untuk alasan akurasi.
Satu hal lagi yang akan saya tambahkan adalah bahwa meskipun Anda tahu aplikasi Anda hanya mendukung bahasa Inggris, mungkin masih perlu berurusan dengan nama orang, yang sering kali dapat berisi karakter yang digunakan dalam bahasa lain di mana sama pentingnya untuk mengurutkan dengan benar . Menggunakan aturan Unicode untuk semuanya membantu menambah ketenangan pikiran bahwa orang-orang Unicode yang sangat pintar telah bekerja sangat keras untuk membuat penyortiran berfungsi dengan baik.
Apa arti bagian-bagian itu
Pertama, ci
untuk penyortiran dan perbandingan case-insensitive . Ini berarti cocok untuk data tekstual, dan kasus tidak penting. Tipe-tipe lain dari collation adalah cs
(case-sensitive) untuk data tekstual di mana case adalah penting, dan bin
, untuk di mana encoding harus cocok, bit for bit, yang cocok untuk bidang yang benar-benar dikodekan data biner (termasuk, misalnya, Base64). Penyortiran case-sensitive mengarah pada beberapa hasil yang aneh dan perbandingan case-sensitive dapat menghasilkan nilai duplikat yang berbeda hanya dalam case letter, sehingga pengumpulan case-sensitive tidak disukai untuk data tekstual - jika case penting bagi Anda, maka tanda baca yang dapat diabaikan dan seterusnya mungkin juga signifikan, dan pemeriksaan biner mungkin lebih tepat.
Berikutnya, unicode
atau general
mengacu pada aturan penyortiran dan perbandingan khusus - khususnya, cara teks dinormalisasi atau dibandingkan. Ada banyak set aturan yang berbeda untuk pengkodean karakter utf8mb4, dengan unicode
dan general
menjadi dua yang berusaha untuk bekerja dengan baik dalam semua bahasa yang mungkin daripada satu yang spesifik. Perbedaan antara kedua perangkat aturan ini adalah subjek dari jawaban ini. Catatan yang unicode
menggunakan aturan dari Unicode 4.0. Versi terbaru dari MySQL menambahkan aturan unicode_520
menggunakan aturan dari Unicode 5.2, dan 0900
(menjatuhkan bagian "unicode_") menggunakan aturan dari Unicode 9.0.
Dan yang terakhir, utf8mb4
tentu saja pengkodean karakter digunakan secara internal. Dalam jawaban ini saya hanya berbicara tentang pengkodean berbasis Unicode.
utf8_general_ci
: itu tidak bekerja. Ini adalah kemunduran ke masa lalu yang buruk dari stooopeeedity ASCII dari lima puluh tahun yang lalu. Pencocokan case-insensitive Unicode tidak dapat dilakukan tanpa peta lipat dari UCD. Misalnya, "Σίσυφος" memiliki tiga sigma yang berbeda di dalamnya; atau bagaimana huruf kecil "TSCHüẞ" adalah "tschüβ", tetapi huruf besar dari "tschüβ" adalah "TSCHÜSS". Anda bisa benar, atau Anda bisa cepat. Karena itu Anda harus menggunakan utf8_unicode_ci
, karena jika Anda tidak peduli tentang kebenaran, maka itu sepele untuk membuatnya sangat cepat.
"か" == "が"
atau "ǽ" == "æ"
. Untuk menyortir ini masuk akal tetapi bisa mengejutkan ketika memilih melalui persamaan atau berurusan dengan indeks unik - bugs.mysql.com/bug.php?id=16526
utf8mb4
adalah satu-satunya pilihan yang benar . Dengan utf8
Anda terjebak dalam beberapa MySQL-only, varian 3-byte UTF8 yang hanya MySQL (dan MariaDB) yang tahu apa yang harus dilakukan. Seluruh dunia menggunakan UTF8, yang dapat memuat hingga 4 byte per karakter . Para pengembang MySQL salah utf8
menyebut penyandian homebrew mereka dan untuk tidak merusak kompatibilitas, mereka sekarang harus merujuk ke UTF8 yang asli utf8mb4
.
Saya ingin tahu apa perbedaan kinerja antara menggunakan utf8_general_ci
dan utf8_unicode_ci
, tetapi saya tidak menemukan benchmark apa pun yang tercantum di internet, jadi saya memutuskan untuk membuat benchmark sendiri.
Saya membuat tabel yang sangat sederhana dengan 500.000 baris:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Lalu saya mengisinya dengan data acak dengan menjalankan prosedur tersimpan ini:
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
Lalu saya membuat prosedur tersimpan berikut untuk membandingkan sederhana SELECT
, SELECT
dengan LIKE
, dan menyortir ( SELECT
dengan ORDER BY
):
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;
Dalam prosedur tersimpan utf8_general_ci
collation digunakan, tetapi tentu saja selama tes saya menggunakan keduanya utf8_general_ci
dan utf8_unicode_ci
.
Saya memanggil setiap prosedur tersimpan 5 kali untuk setiap pemeriksaan (5 kali untuk utf8_general_ci
dan 5 kali untuk utf8_unicode_ci
) dan kemudian menghitung nilai rata-rata.
Hasil saya adalah:
benchmark_simple_select()
utf8_general_ci
: 9,957 ms utf8_unicode_ci
: 10.271 ms Dalam benchmark ini menggunakan utf8_unicode_ci
lebih lambat dibandingkan utf8_general_ci
dengan 3,2%.
benchmark_select_like()
utf8_general_ci
: 11.441 ms utf8_unicode_ci
: 12.811 ms Dalam benchmark ini menggunakan utf8_unicode_ci
lebih lambat dibandingkan utf8_general_ci
dengan 12%.
benchmark_order_by()
utf8_general_ci
: 11.944 ms utf8_unicode_ci
: 12.887 ms Dalam benchmark ini, penggunaan utf8_unicode_ci
lebih lambat dibandingkan utf8_general_ci
dengan 7,9%.
utf8_general_ci
terlalu kecil untuk layak digunakan.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
hanya menghasilkan ASCII, dan tidak ada karakter Unicode yang akan diproses oleh algoritma dari kumpulan. 2) Description = 'test' COLLATE ...
dan Description LIKE 'test%' COLLATE ...
hanya memproses string tunggal ("test") saat runtime, bukan? 3) Dalam aplikasi nyata, kolom yang digunakan dalam pemesanan mungkin akan diindeks, dan kecepatan pengindeksan pada berbagai koleksi dengan teks non-ASCII nyata mungkin berbeda.
Posting ini menggambarkannya dengan sangat baik.
Singkatnya: utf8_unicode_ci menggunakan Algoritma Collation Unicode sebagaimana didefinisikan dalam standar Unicode, sedangkan utf8_general_ci adalah urutan penyortiran yang lebih sederhana yang menghasilkan hasil penyortiran "kurang akurat".
utf8_unicode_ci
dan pura-pura yang lain tidak ada.
utf8_general_ci
mungkin untuk Anda
Lihat manual mysql, bagian Set Karakter Unicode :
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.
Jadi untuk meringkas, utf_general_ci menggunakan set perbandingan yang lebih kecil dan kurang benar (sesuai dengan standar) daripada utf_unicode_ci yang harus mengimplementasikan seluruh standar. Set general_ci akan lebih cepat karena ada sedikit komputasi yang harus dilakukan.
utf8_unicode_ci
dan berpura-pura versi kereta yang rusak tidak ada.
0
dan 1
, bukan bool. :) EG memilih titik geo dalam kotak pembatas adalah perkiraan 'titik terdekat' yang tidak sebaik menghitung jarak antara titik dan titik referensi dan memfilternya. Tetapi keduanya merupakan perkiraan dan pada kenyataannya, kebenaran lengkap sebagian besar tidak dapat dicapai. Lihat paradoks garis pantai dan IEEE 754
1/3
Secara singkat:
Jika Anda memerlukan urutan penyortiran yang lebih baik - gunakan utf8_unicode_ci
(ini adalah metode yang disukai),
tetapi jika Anda benar-benar tertarik pada kinerja - gunakan utf8_general_ci
, tetapi ketahuilah bahwa itu sedikit ketinggalan jaman.
Perbedaan dalam hal kinerja sangat kecil.
Seperti yang dapat kita baca di sini ( Peter Gulutzan ) ada perbedaan dalam menyortir / membandingkan huruf polish "Ł" (L dengan stroke - html esc:) Ł
(huruf kecil: "ł" - html esc:) ł
- kami memiliki asumsi berikut:
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
Dalam bahasa Polandia, huruf Ł
adalah setelah huruf L
dan sebelumnya M
. Tidak ada satu pun dari pengkodean ini yang lebih baik atau lebih buruk - itu tergantung kebutuhan Anda.
Ada dua perbedaan besar antara penyortiran dan pencocokan karakter:
Menyortir :
utf8mb4_general_ci
menghapus semua aksen dan pengurutan satu per satu yang dapat membuat hasil pengurutan yang salah.utf8mb4_unicode_ci
macam akurat.Pencocokan Karakter
Mereka mencocokkan karakter secara berbeda.
Misalnya, di utf8mb4_unicode_ci
Anda miliki i != ı
, tetapi di utf8mb4_general_ci
dalamnya berlaku ı=i
.
Misalnya, bayangkan Anda memiliki pertengkaran name="Yılmaz"
. Kemudian
select id from users where name='Yilmaz';
akan mengembalikan baris jika kolokasi adalah utf8mb4_general_ci
, tetapi jika collocated dengan utf8mb4_unicode_ci
itu tidak akan mengembalikan baris!
Di sisi lain kita memiliki a=ª
dan ß=ss
di utf8mb4_unicode_ci
mana tidak terjadi di utf8mb4_general_ci
. Jadi bayangkan Anda memiliki pertengkaran name="ªßi"
, lalu
select id from users where name='assi';
akan mengembalikan baris jika kolokasi utf8mb4_unicode_ci
, tetapi tidak akan mengembalikan baris jika kolokasi diatur ke utf8mb4_general_ci
.
Daftar lengkap kecocokan untuk setiap kolokasi dapat ditemukan di sini .
Menurut posting ini, ada manfaat kinerja yang sangat besar pada MySQL 5.7 ketika menggunakan utf8mb4_general_ci sebagai ganti utf8mb4_unicode_ci: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-kinerja /