UTF-8: ทั่วไปใช่ไหม Bin? Unicode?


279

ฉันกำลังพยายามหาการเปรียบเทียบที่ฉันควรใช้สำหรับข้อมูลประเภทต่างๆ เนื้อหา 100% ที่ฉันจะจัดเก็บนั้นเป็นแบบที่ผู้ใช้ส่ง

ความเข้าใจของฉันคือฉันควรใช้ UTF-8 General CI (ตัวพิมพ์เล็ก - ใหญ่) แทน UTF-8 Binary อย่างไรก็ตามฉันไม่สามารถค้นหาความแตกต่างที่ชัดเจนระหว่าง UTF-8 General CI และ UTF-8 Unicode CI

  1. ฉันควรจัดเก็บเนื้อหาที่ผู้ใช้ส่งในคอลัมน์ UTF-8 General หรือ UTF-8 Unicode CI หรือไม่
  2. ข้อมูลประเภทใดที่จะใช้กับ UTF-8 Binary?

16
หมายเหตุด้านข้าง แต่แทนที่จะutf8ใช้utf8mb4แทนการรองรับ UTF-8 แบบเต็ม แสดงความคิดเห็นที่นี่เพราะคำตอบของคำถามยอดนิยมนี้ไม่ได้ตอบคำถามนี้ mathiasbynens.be/notes/mysql-utf8mb4
Steven R. Loomis

หากคุณต้องการพับกรณี แต่ความไวสำเนียงโปรดยื่นคำขอที่bugs.mysql.com
Rick James

หรือคลิก "มีผลต่อฉัน" ในbugs.mysql.com/bug.php?id=58797และเพิ่มความคิดเห็น
Rick James

คำตอบ:


299

โดยทั่วไปutf8_general_ciเร็วกว่าutf8_unicode_ciแต่ถูกต้องน้อยกว่า

นี่คือความแตกต่าง:

สำหรับการใด ๆ ชุดอักขระ Unicode การดำเนินการดำเนินการโดยใช้การเปรียบเทียบ _general_ci จะเร็วกว่าสำหรับการเปรียบเทียบ ตัวอย่างเช่นการเปรียบเทียบสำหรับการเปรียบเทียบ utf8_general_ci นั้นเร็วกว่า แต่ถูกต้องน้อยกว่าการเปรียบเทียบสำหรับ utf8_unicode_ci เหตุผลสำหรับสิ่งนี้คือ utf8_unicode_ci รองรับการแมปเช่นการขยาย นั่นคือเมื่อตัวละครตัวหนึ่งเปรียบเทียบเท่ากับการรวมกันของตัวละครอื่น ๆ ตัวอย่างเช่นในภาษาเยอรมันและภาษาอื่น ๆ “ ß” เท่ากับ“ ss” utf8_unicode_ci ยังรองรับตัวย่อและอักขระที่ละเว้น utf8_general_ci คือการเปรียบเทียบแบบดั้งเดิมที่ไม่รองรับการขยายตัวย่อหรือตัวอักษรที่เพิกเฉย มันสามารถทำการเปรียบเทียบแบบหนึ่งต่อหนึ่งระหว่างตัวละคร

อ้างอิงจาก: http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html

สำหรับคำอธิบายโดยละเอียดเพิ่มเติมโปรดอ่านโพสต์ต่อไปนี้จากฟอรั่ม MySQL: http://forums.mysql.com/read.php?103,187048,188748

สำหรับ utf8_bin: ทั้งutf8_general_ciและutf8_unicode_ciทำการเปรียบเทียบแบบคำนึงถึงขนาดตัวพิมพ์ ในconstrast utf8_bin จะคำนึงถึงขนาดตัวพิมพ์ (ในความแตกต่างอื่น ๆ ) เนื่องจากเป็นการเปรียบเทียบค่าไบนารีของอักขระ


2
ฉันคิดว่าถ้าคุณไม่มีเหตุผลที่ดีในการใช้ _unicode_ci ให้ใช้ _general_ci
Sagi

4
สิ่งนี้ไม่ได้ตอบคำถามในเชิงลึก ความแตกต่างระหว่างการเปรียบเทียบเหล่านี้คืออะไร?
Pekka

4
คุณพูดถูกความแตกต่างที่แท้จริงนั้นไม่ได้ให้ไว้ที่นี่เพื่อความเรียบง่าย ฉันได้เพิ่มลิงก์ไปยังโพสต์ที่มีความแตกต่างที่แน่นอน
Sagi

NB show collation;อนุญาตให้คุณเห็นการเรียงหน้าเริ่มต้นสำหรับชุดอักขระแต่ละชุด 5.1 แสดงให้เห็นว่าเป็นค่าเริ่มต้นสำหรับutf8_general_ci utf8
David Carboni

9
มีทรัพยากรใดบ้างที่จะไปในเชิงลึกมากขึ้นในความแตกต่างของความเร็วที่แท้จริงระหว่างการเปรียบเทียบสองครั้ง? เรากำลังพูดถึงการลดลงของประสิทธิภาพ 0.1% หรือลดลง 10%?
Emphram Stavanger

90

คุณควรตระหนักถึงความจริงว่าด้วย utf8_general_ci เมื่อใช้ฟิลด์ varchar เป็นดัชนีที่ไม่ซ้ำกันหรือหลักที่ใส่ 2 ค่าเช่น 'a' และ 'á' จะให้ข้อผิดพลาดที่สำคัญซ้ำกัน


3
ขอบคุณสิ่งนี้มีประโยชน์ในการหลีกเลี่ยงชื่อผู้ใช้ที่คล้ายกัน (เช่นหากมี "jose" อยู่ฉันไม่ต้องการให้คนอื่นสร้างผู้ใช้ "josé") หมายเหตุ: สิ่งนี้ถือเป็นจริงสำหรับการเปรียบเทียบ utf8 เกือบทั้งหมด (ยกเว้น utf8_bin) ที่ปลอดภัยที่สุด / ปลอดภัยที่สุด / ครอบคลุมมากที่สุดคือutf8_unicode_ci
คอสตา

2
ฉันใช้ utf8_bin โดยที่ฉันต้องการให้ jose และjoséโดดเด่นในดัชนี ตัวอย่างเช่นคอลัมน์ที่บันทึกการดำเนินการค้นหา / แทนที่โดยที่ผู้ใช้อาจตัดสินใจค้นหาjoséและแทนที่ด้วย jose (ฉันกำลังเขียนโปรแกรมสเปรดชีต)
Buttle Butkus

33
  • utf8_binเปรียบเทียบบิตสุ่มสี่สุ่มห้า กรณีไม่พับไม่มีการลอกสำเนียง
  • utf8_general_ciเปรียบเทียบหนึ่งไบต์กับหนึ่งไบต์ มันจะทำการพับและเน้นการลอก แต่ไม่มีการเปรียบเทียบ 2 ตัวอักษร: ijไม่เท่ากันijในการเปรียบเทียบนี้
  • utf8_*_ciเป็นชุดของกฎเฉพาะภาษา unicode_ciแต่อย่างอื่นเช่น บางกรณีพิเศษ: Ç, Č, ch,ll
  • utf8_unicode_ciปฏิบัติตามมาตรฐาน Unicode เก่าสำหรับการเปรียบเทียบ ij= ij, แต่ae! =æ
  • utf8_unicode_520_ciเป็นไปตามมาตรฐาน Unicode ที่ใหม่กว่า ae=æ

ดูแผนภูมิการเปรียบเทียบเพื่อดูรายละเอียดเกี่ยวกับสิ่งที่เท่ากับในการเปรียบเทียบ utf8 ต่างๆ

utf8, ตามที่กำหนดโดย MySQLจะถูก จำกัด รหัส utf8 1- 3 ไบต์ นี่ทำให้ Emoji และจีนบางส่วนหมดไป ดังนั้นคุณควรเปลี่ยนไปใช้utf8mb4ถ้าคุณต้องการไปไกลกว่ายุโรปมาก

ประเด็นข้างต้นนำไปใช้กับutf8mb4หลังจากการเปลี่ยนแปลงการสะกดคำที่เหมาะสม ก้าวไปข้างหน้าutf8mb4และutf8mb4_unicode_520_ciเป็นที่ต้องการ

  • utf16 และ utf32 เป็นตัวแปรใน utf8; แทบไม่มีประโยชน์อะไรเลยสำหรับพวกเขา
  • ucs2 ใกล้เคียงกับ "Unicode" มากกว่า "utf8"; แทบไม่มีประโยชน์อะไรเลย

1
เรื่อง "คอยติดตาม": การเปรียบเทียบ 8.0แสดงให้เห็นว่าตัวละครต่างๆ, คำควบกล้ำ, อื่น ๆ , เปรียบเทียบในการเปรียบเทียบ 8.0 utf8mb4; utf8 ส่วนใหญ่เหมือนกัน
Rick James

และการเปรียบเทียบ 8.0 จะถูกตอกบัตรที่ความเร็วอย่างรวดเร็วกว่า 5.x
Rick James

มันจะดีถ้าหน้านั้นแสดง utf8mb4_bin ที่ด้านบน ฉันรู้ว่ามันไม่ตรงกับตัวละครเลย แต่มันก็ดีสำหรับมือใหม่
Henk Poley

6

จริง ๆ แล้วฉันทดสอบค่าการบันทึกเช่น 'é' และ 'e' ในคอลัมน์ด้วยดัชนีที่ไม่ซ้ำกันและพวกเขาทำให้เกิดข้อผิดพลาดซ้ำกันทั้ง 'utf8_unicode_ci' และ 'utf8_general_ci' คุณสามารถบันทึกได้ในคอลัมน์ 'utf8_bin' ที่เรียงรวมเท่านั้น

และ mysql docs (ในhttp://dev.mysql.com/doc/refman/5.7/en/charset-applications.html ) แนะนำให้เป็นตัวอย่างการตั้งค่าการจัดเรียง 'utf8_general_ci' ตัวอย่าง

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

1
ฉันทำการทดสอบอย่างรวดเร็วเกี่ยวกับเรื่องนี้และดูเหมือนว่าจะถูกต้อง การเปรียบเทียบทั้งสองจะทำงานเหมือนกันเมื่อมันมาถึงคีย์ที่ไม่ซ้ำกันในคอลัมน์และค่าที่มี tildes และสิ่งที่คล้ายกัน
MirroredFate

@MirroredFate ตกลงฉันควรเพิ่มที่นั่นคอลัมน์ควรมีดัชนีเฉพาะที่ทำให้เกิดข้อผิดพลาดนี้ มันมีความหมายในคำตอบของฉัน
vitalii

3

คำตอบที่ยอมรับนั้นล้าสมัยแล้ว

หากคุณใช้ MySQL 5.5.3+ ให้ใช้utf8mb4_unicode_ciแทนutf8_unicode_ciเพื่อให้แน่ใจว่าอักขระที่พิมพ์โดยผู้ใช้ของคุณจะไม่ทำให้เกิดข้อผิดพลาด

utf8mb4รองรับอีโมจิในขณะที่utf8อาจให้ข้อบกพร่องที่เกี่ยวข้องกับการเข้ารหัสหลายร้อยรายการเช่น:

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


คำตอบนี้ (ถูกต้อง) แก้ไขปัญหาการเข้ารหัส Emoji (และภาษาจีนบางส่วน) แต่คำถามดูเหมือนจะเน้นไปที่การเรียงหน้า utf8mb4_unicode_ciถือว่า (ฉันคิดว่า) อิโมจิทุกคนเท่ากัน utf8mb4_unicode_520_ciให้การสั่งซื้อ Emoji
Rick James
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.