ควรใช้ Latin-1 มากกว่า UTF-8 เมื่อพูดถึงการกำหนดค่าฐานข้อมูลหรือไม่?


65

เรากำลังใช้งาน MySQL ที่ บริษัท ที่ฉันทำงานอยู่และเราสร้างทั้งแอปพลิเคชันสำหรับลูกค้าและภายในโดยใช้ Ruby on Rails

เมื่อฉันเริ่มทำงานที่นี่ฉันพบปัญหาที่ฉันไม่เคยพบมาก่อน ฐานข้อมูลบนเซิร์ฟเวอร์ที่ใช้งานถูกตั้งค่าเป็น Latin-1 ซึ่งหมายความว่า MySQL มีข้อผิดพลาดเมื่อใดก็ตามที่มีการป้อนข้อมูลของผู้ใช้ที่ผู้ใช้คัดลอกและวางอักขระ UTF-8

เจ้านายของฉันเรียกว่า "ตัวละครที่ไม่ดี" เหล่านี้เนื่องจากส่วนใหญ่เป็นตัวละครที่ไม่สามารถพิมพ์ได้และบอกว่าเราต้องถอดมันออก ฉันได้พบวิธีในการทำเช่นนี้ แต่ในที่สุดเราก็ลงเอยด้วยสถานการณ์ที่จำเป็นต้องใช้อักขระ UTF-8 นอกจากนี้ยังเป็นเรื่องยุ่งยากโดยเฉพาะอย่างยิ่งเนื่องจากดูเหมือนว่าทางออกเดียวที่ฉันเคยอ่านเกี่ยวกับปัญหานี้คือการตั้งค่าฐานข้อมูลเป็น UTF-8 (เหมาะสมกับฉัน)

อาร์กิวเมนต์เดียวที่ฉันได้ยินมาสำหรับการใช้ภาษาละติน -1 คือการอนุญาตให้ใช้ตัวอักษร UTF-8 ที่ไม่สามารถพิมพ์ได้สามารถทำให้การค้นหาข้อความ / ข้อความแบบเต็มใน MySQL นี่เป็นเรื่องจริงหรือ

มีเหตุผลอื่นอีกหรือไม่ที่เราควรใช้ Latin-1 แทน UTF-8 ฉันเข้าใจว่ามันยอดเยี่ยมและแพร่หลายมากขึ้น


4
@jon LATIN-1 ไม่เจาะจงภาษาอังกฤษ สเปนมีอยู่อย่างสมบูรณ์เช่นเดียวกับฝรั่งเศสถ้าฉันไม่เข้าใจผิด
Darkhogg

4
@Darkhog: Latin1 ไม่เฉพาะเจาะจงสำหรับภาษาอังกฤษ แต่เป็นข้อ จำกัด หลักในตัวอักษรตะวันตกยุโรป
Bart van Ingen Schenau

16
ประโยชน์ที่เป็นไปได้เพียงอย่างเดียวจากการใช้ภาษาละติน 1 มากกว่า UTF-8 ในระบบที่ทันสมัยคือการก่อวินาศกรรม แน่นอนว่าเป็นประโยชน์ต่อผู้ก่อวินาศกรรมและผู้ที่ภักดีต่อพวกเขาจะต้องไม่เป็นเจ้าของหรือผู้พัฒนาระบบ
Jon Hanna

13
น่าเสียดายที่ฐานข้อมูลของคุณจะไม่สามารถถือสัญลักษณ์ยูโรหรือแม้แต่ชื่อของฉัน (דותן)
dotancohen

20
ผู้ใช้ "คัดลอกและวาง" อักขระที่ไม่ใช่ latin-1? อย่าปฏิบัติต่อยูนิโค้ดเพราะสิ่งที่ไม่สำคัญที่ไม่สำคัญซึ่งเป็นสิ่งที่ผู้สนใจเท่านั้นที่ใส่ใจ พวกเราหลายคนพิมพ์ตัวละครที่ไม่เข้ากับละติน -1 เป็นประจำ - ฉันได้ยินผู้คนมากมายพูดภาษานอกยุโรปแม้♥
Eevee

คำตอบ:


131

Unicode นั้นยากและการเข้ารหัส UTF-8 มีคุณสมบัติที่ไม่สะดวกสองอย่าง อย่างไรก็ตาม UTF-8 ได้กลายเป็นการเข้ารหัสมาตรฐานแบบ de-facto บนเว็บซึ่งเหนือกว่า ASCII, Latin-1, UCS-2 และ UTF-16 เพียงแค่ใช้ UTF-8 ทุกที่

เหตุผลที่สำคัญที่สุดที่คุณควรสนับสนุน Unicode คือคุณไม่ควรตั้งสมมติฐานที่ไม่จำเป็นเกี่ยวกับอินพุตของผู้ใช้ ฉันไม่รู้ว่าโดเมนของคุณคืออะไร แต่ชื่อผู้ใช้ภาษาฮิบรูบล็อกโพสต์เกี่ยวกับประเทศจีนความคิดเห็นที่มี Emoji หรือข้อความที่มีสไตล์ - เช่น "นี่" - น่าจะเป็นไปได้…โอ้มันเป็นเครื่องหมายคำพูดที่ถูกต้อง“”แทน""), เครื่องหมายขีดกลางกว้างและจุดไข่ปลาซึ่งเป็นอักขระที่พบบ่อยในข้อความภาษาอังกฤษ แต่ไม่รองรับโดย ASCII หรือละติน -1 ดังนั้นการไม่สนับสนุนสคริปต์อื่น ๆ ไม่ได้เป็นเพียงแค่ f * ck ที่ยิ่งใหญ่สำหรับคุณในวัฒนธรรมอื่น ๆ แต่การใช้ภาษาละติน -1 ไม่ได้ช่วยให้คุณสามารถเขียนภาษาอังกฤษได้อย่างเหมาะสม

ความคิดที่ Unicode อนุญาตเฉพาะ“ ตัวละครที่ไม่ดี” นั้นผิด ใช่ข้อความนั้นซับซ้อนจริงๆและ Unicode จะไม่ซ่อนสิ่งนั้นจากคุณ เจ้านายของคุณอาจจะคิดเกี่ยวกับตัวละครประกอบที่หนึ่งฐาน codepoint เช่นaมีการแก้ไขโดย codepoints áตามมาว่าเช่นแทนกำกับในรูปแบบตัวอักษรภาพหนึ่งเช่น สิ่งนี้ไม่ได้เป็นไปตามที่คุณต้องการเมื่อพยายามทำการค้นหาถ้าคุณใช้การทำให้เป็นมาตรฐาน ตัวอย่างเช่นคุณสามารถเก็บข้อความทั้งหมดในรูปแบบ NFC ซึ่งยุบองค์ประกอบดังกล่าวลงในแบบฟอร์มที่คอมไพล์แล้วหากมีให้ใช้ เมื่อทำการค้นหาคุณสามารถตัดอักขระการเขียนทั้งหมดออกจากข้อความได้ แต่สิ่งนี้อาจเปลี่ยนความหมายของพวกเขาในบางภาษาได้อย่างมาก

Unicode ยังเพิ่มอักขระที่ไม่สามารถพิมพ์ได้จำนวนมาก - แต่ถึงแม้ ASCII จะมีอักขระมากมาย คุณจะจัดการกับ NUL ที่อยู่ตรงกลางของสตริงหรือไม่? วิธีการเกี่ยวกับ 0x1C, "ตัวแยกไฟล์"? ผมไม่เคยเห็นครึ่งหนึ่งของผู้ Latin-1 เพิ่มยัติภังค์อ่อน ๆ ที่ระบุโอกาสในการแตกคำ แต่ไม่สามารถมองเห็นได้ สิ่งนั้นยังทำลายการค้นหาข้อความแบบเต็มของคุณหรือไม่ กล่าวอีกนัยหนึ่งแม้แต่ ASCII และ Latin-1 ยังช่วยให้คุณสามารถแยกอินพุตของคุณได้อย่างสมบูรณ์ถ้าคุณคิดว่ามันเป็นเพียงข้อความที่พิมพ์ได้!


8
จากมุมมองฐานข้อมูลอักขระบางตัวไม่อนุญาตให้ใช้ในฟิลด์ชนิดข้อความ (text / varchar / char / etc) MySQL ไม่อนุญาตให้ตัวละครโมฆะในชนิดข้อมูลเหล่านี้ แต่ฐานข้อมูลอื่น ๆ เช่น PostgreSQL ไม่ คุณควรจะใช้ BLOB (MySQL) หรือ BYTEA (PostgreSQL) ถ้าคุณต้องการที่จะสามารถเก็บตัวอักษรดังกล่าว
cimmanon

15
"การเกาะติดกับละติน -1 ไม่อนุญาตให้คุณเขียนภาษาอังกฤษที่เหมาะสม" นั่นเป็นสิ่งที่ดีมิฉะนั้นยูนิโค้ดก็จะยิ่งแข็งแกร่งขึ้น ;-)
Deduplicator

3
@ PaŭloEbermannอักขระ NUL ในตัวหมายถึงข้อมูลของคุณเป็นแบบไบนารีไม่ใช่เพียงแค่สตริง NUL เป็นตัวอย่างที่แปลกเนื่องจากฉันเชื่อว่า UTF-8 หลีกเลี่ยงการใช้\0ไบต์เป็นส่วนหนึ่งของการเข้ารหัสแบบหลายไบต์เพื่อให้แน่ใจว่าโค้ดที่ไม่ใช่ UTF8 ไม่ได้หยุดอยู่ตรงกลางสตริง
Peter Cordes

7
อักขระยูนิโค้ดทั้งหมดสามารถพิมพ์ได้ - คุณเพียงแค่ต้องใช้ตัวอักษรที่ถูกต้อง :-)
James Anderson

4
@ JamesAnderson ตัวอักษรนั้นจะผิดและแตก en.wikipedia.org/wiki/Unicode_control_characters
djechlin

62

ฉันคิดว่านอกเหนือจากคำถามทางเทคนิคแล้วหัวหน้าของคุณอาจไม่มีเวลาที่จะติดตามความคืบหน้าของมาตรฐานปัจจุบัน

เนื่องจากท่าทางของเขาไม่ได้รับประทานอาหารกลางวันอย่างสมบูรณ์เพียงแค่ล้าสมัยเคารพตำแหน่งของเขาเมื่อพูดถึงเรื่องนี้ (และคุณต้องจำไว้เพื่อพูดคุยไม่เถียง) และพยายามทำงานผ่านข้อกังวลที่เขามีเกี่ยวกับ UTF-8 ฉันสงสัยว่าปัญหาพื้นฐานไม่ใช่ปัญหาด้านเทคนิคและอาจต้องใช้การเจรจาต่อรองในระดับอ่อนนุ่ม


6
ฉันไม่สามารถอนุมัติเพิ่มเติมได้ ที่จริงฉันเสียใจที่คำตอบของฉันเองฉันมองข้าม "ฝ่ายมนุษย์" อย่างสมบูรณ์ซึ่งในประเด็นนี้อาจจะเป็นสิ่งสำคัญยิ่ง หวังว่าฉันจะ upvote มากกว่าหนึ่งครั้ง :-)
LSerni

2
เรียกทุกอย่างนอกละติน -1 bad characterและคิดว่าสิ่งเหล่านี้non-printableเป็นของjust out-datedคุณ
njzk2

2
ปัญหาที่แท้จริงคือ "มันเป็นปัญหาทางเทคนิคที่เรากำลังเผชิญอยู่หรือไม่" ฉันไม่เชื่อว่าหัวหน้าของ OP ไปโรงเรียนและได้รับการสอนนี้หรืออ่านคู่มือ / วารสารทางเทคนิคและมาถึงข้อสรุปนั้น ฉันไม่เข้าใจว่าโซลูชันนี้เป็นโซลูชันทางเทคนิคอย่างเคร่งครัด แดกดันความคิดเห็นที่แสดงให้เห็นว่าหัวใจของปัญหา; การแก้ไขปัญหานี้อาจทำให้เกิดความไม่พอใจอย่างมากหากดำเนินการไม่เหมาะสม
เนลสัน

49

พวกเราคนไหนถูก

กาลครั้งหนึ่งเจ้านายของคุณเป็น แต่เมื่อเวลาผ่านไปสิ่งต่าง ๆ เปลี่ยนไป ทุกวันนี้คุณเป็น (แต่ก่อนที่จะวิ่งไปหาหัวหน้าคุณต้องอ่านคำตอบของเนลสันด้วย )

MySQL รุ่นเก่าและทุกอย่างเป็นเวอร์ชั่นเก่าจัดการได้ดีกว่ากับ Latin1 / ISO-8859-1 (5) มากกว่า UTF8 ที่เก่ากว่า

มีเหตุผลที่ UTF8 ถูกสร้างพัฒนาและผลักดันส่วนใหญ่ในทุกที่: หากมีการใช้งานอย่างถูกต้องมันจะทำงานได้ดีกว่ามาก มีปัญหาด้านประสิทธิภาพและการจัดเก็บบางส่วนที่เกิดจากข้อเท็จจริงที่ว่าตัวอักษร Latin1 คือ 8 บิตในขณะที่อักขระ UTF8 อาจมีความยาวตั้งแต่ 8 ถึง 32 บิต ดังนั้นเมื่อวางแผนVARCHARคุณต้องคำนึงถึงเรื่องนี้ด้วย และขั้นตอนการค้นหาของคุณจะช้าลงเล็กน้อย พวกเขาจะสามารถทำสิ่งต่าง ๆ ได้มากขึ้น (เช่นการค้นหาที่เน้นความอ่อนไหวหรือไม่มีไม่สามารถทำได้ในละติน 1 โดยไม่ต้องทำงานหนัก) แต่พวกเขาจะใช้เวลาอีกเล็กน้อย

แต่ในมืออื่น ๆ ที่จัดเก็บข้อมูลราคาถูกที่จริงค่าใช้จ่ายเกี่ยวกับขนาดไฟล์น้อยกว่า 2-3%, อำนาจการใช้คอมพิวเตอร์ยังมีราคาถูกและได้รับราคาถูกตามที่ดีกับกฎของมัวร์; ในขณะที่เวลาของคุณและความคาดหวังของลูกค้าแน่นอนไม่ได้

คุณอาจต้องกังวลกับเครื่องมือค้นหาเป็นต้นหากคุณเป็นผู้พัฒนาเครื่องมือดังกล่าว แต่คุณอาจจะไม่ คุณใช้เครื่องมือเหล่านั้น แม้กระทั่งที่ไม่ได้เป็นไปตาม UTF8 อย่างสมบูรณ์เมื่อวานนี้ (อย่างที่ไม่เคยมีมาก่อนของ MySQL), เป็นทุกวันนี้, หรือเร็ว ๆ นี้จะเป็น (เช่น MySQL ที่มีการสนับสนุน utf8mb4)

ดังนั้นโดยการวางแผนและการนำ UTF8 ไปใช้อย่างถูกวิธี ( ไม่ควรใช้ภาษาละตินมากกว่า 1 ในภายหลัง) คุณสามารถมีรหัสที่มีความเป็นไปได้ในอนาคตซึ่งถ้าคุณวางแผนที่จะทำธุรกิจกับประเทศในแถบเอเซีย สิ่ง. และถ้าคุณไม่มีแผนดังกล่าวคนอื่นจะมีและคนเหล่านั้นอาจเป็นลูกค้าซัพพลายเออร์หรือพันธมิตรของคุณ

ดังนั้นเมื่อพวกเขาเริ่มส่งข้อมูล UTF8 ให้คุณคุณจะต้องตั้งค่าสิ่งที่ซับซ้อนเพื่อแปลงเป็นเทียวมาติน 1 และจัดการกับกรณีที่แก้ไม่ได้

เมื่อคุณคำนึงถึงงบประมาณค่าใช้จ่ายในการต่อสู้หลายครั้งกับนินจาโมจิเบคที่ชั่วร้ายและพิจารณาว่าพวกเขาจะไม่หายไป - ตามที่คุณค้นพบแล้ว - คุณจะรู้ว่าการไป UTF8 นั้นไม่เพียง แต่ง่ายกว่าเท่านั้นราคาถูกกว่าเช่นกัน


4

บางสถานการณ์ที่การ จำกัด อักขระที่ตั้งค่าเป็น ASCII อาจเหมาะสมสำหรับฟิลด์ตัวเลือกที่ จำกัด เช่นฟิลด์สถานะเนื่องจากคุณควบคุมค่าที่สามารถมีอย่างเคร่งครัดและคีย์ต่างประเทศ / การอ้างอิงไปยังระบบภายนอกเนื่องจากไม่ค่อยมีเหตุผลใด ๆ สำหรับ พวกเขามีอะไรก็ได้ยกเว้นตัวอักษรและตัวเลขและสัญลักษณ์บางอย่าง

สำหรับข้อความอื่น ๆ เพียงใช้ UTF-8


2
MySQL ไม่มี enums เหรอ?
raptortech97

2
และเนื่องจาก ASCII เป็นเซตย่อยของ UTF8 เพียงแค่ใช้ UTF8 แม้ในตอนนั้น
RemcoGerlich

@RemcoGerlich: ฉันไม่เห็นด้วยที่คุณสามารถใช้ UTF8 ได้ ในมุมมองของฉันการอ้างอิงภายนอกไม่ใช่ข้อความ แต่เป็นลำดับทึบแสงของไบต์ ไม่มีชุดอักขระยกเว้นเพื่อความสะดวกสบาย หากลำดับของไบต์มีการตีความในชุดอักขระบางตัวนั่นคือทั้งโดเมนภายนอกหรือโดเมนของแอปพลิเคชันไม่ใช่ของฐานข้อมูล
Lie Ryan

3
@LieRyan: ฉันเห็นจุดนั้น แต่ก็ไม่ควรเป็น ASCII อย่างใดอย่างหนึ่งอาจเป็นรูปแบบไบนารีหยดหรือดังนั้น
RemcoGerlich

3

ในการเริ่มต้นด้วยคำตอบมันไม่สำคัญว่าเซิร์ฟเวอร์ของคุณได้รับการกำหนดค่าอย่างไร การเข้ารหัสตัวอักษรใน MySQL สามารถกำหนดค่าต่อคอลัมน์ (หมายถึงตารางเดียวกันสามารถเก็บอักขระในการเข้ารหัสหลาย ๆ ตัวได้ง่าย) คือเซิร์ฟเวอร์ของฉัน (และฐานข้อมูลดั้งเดิมจำนวนหนึ่ง) ถูกกำหนดค่าสำหรับ cp1251 โดยค่าเริ่มต้นสำหรับลูกค้าเก่าที่ไม่สามารถตั้งค่าการเรียงที่ถูกต้องเมื่อเชื่อมต่อ (ไคลเอนต์ฮาร์ดแวร์ที่แตกต่างกัน) แต่ฐานข้อมูลหลักในการผลิตล้วนใช้ UTF-8

การพูดถึง "พื้นที่ที่สูญเปล่า" - คุณไม่สามารถเรียกข้อมูลที่สำคัญว่าเป็นขยะได้จริงไหม? พื้นที่เก็บข้อมูลเพิ่มขึ้น แต่จะแตกต่างกันไปตามภาษาที่ข้อมูลของคุณเพิ่มขึ้นเล็กน้อย (น้อยกว่า 1%) เพิ่มขึ้นหากไซต์ของคุณเป็นภาษาอังกฤษเป็นหลักและสูงถึง 100% หากเป็น Mailny โดยใช้อักขระที่อยู่นอกช่วง ASCII . และยิ่งไปกว่านั้นถ้าคุณย้ายไปทางทิศตะวันออกมากขึ้น ข้อกำหนดในภายหลัง UTF-8 (เรียกว่า UTF8mb4) อนุญาตให้มีได้สูงสุด 4 ไบต์ต่อจุดโค้ด

และสำหรับ "ใครถูก" …ความจริงก็คือนี่เป็นคำถามทางสังคมมากกว่าที่เป็นเรื่องทางเทคนิค อาจมีเหตุผลที่ถูกต้องสำหรับการตั้งค่าเซิร์ฟเวอร์เฉพาะ แต่คุณต้องทราบความหมาย แต่ถ้าคุณถามฉันไม่มีเหตุผลที่จะไม่ใช้ UTF-8 มันเป็นชนิดเดียวที่จะปกครองข้อความทั้งหมดในโลก


MySQL จะพยายามแปลงข้อมูลในการเข้ารหัสฐานข้อมูลก่อนที่จะแปลงเป็นการเข้ารหัสคอลัมน์ หากคุณมีไคลเอ็นต์ utf8 ฐานข้อมูล latin1 และคอลัมน์ utf8 ดังนั้นข้อมูลข้อความอาจสูญหายได้
Ivan Solntsev

อีวานนั่นเป็นคำถามที่แตกต่างอย่างสิ้นเชิง ปฏิสัมพันธ์ระหว่างชุดอักขระไคลเอนต์ชุดอักขระเซิร์ฟเวอร์เชื่อมต่อชุดอักขระชุดอักขระผลลัพธ์เป็นบทความยาวในเอกสาร MySQL และในกรณีของการตั้งค่าการเรียงคอลัมน์ต่อ "การเปรียบเทียบฐานข้อมูล" คือการจัดเรียงคอลัมน์และจะถูกแปลงเป็นชุดอักขระผลลัพธ์โดยตรงโดยไม่สนใจการเปรียบเทียบฐานข้อมูล
AnrDaemon

0

เพียงอธิบายให้เขาทราบว่า UTF-8 เป็นค่าเริ่มต้นสำหรับปริมาณการใช้งานเว็บ และผู้ใช้สามารถป้อนอักขระ Unicode ที่ถูกต้องในเบราว์เซอร์ของตน

มันง่ายกว่ามากที่จะมี utf-8 / unicode ตลอดทางจากปลายด้านหน้าถึงปลายด้านหลังมากกว่าที่จะจัดการกับปัญหามากมายและหลากหลายที่เป็นผลมาจาก utf-8-> latin-1-> utf-8

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.