utf8_general_ci และ utf8_unicode_ci แตกต่างกันอย่างไร


1063

ระหว่างutf8_general_ciและutf8_unicode_ciมีความแตกต่างในแง่ของประสิทธิภาพหรือไม่



6
ถ้าคุณชอบutf8[mb4]_unicode_ciคุณอาจจะชอบutf8[mb4]_unicode_520_ciมากกว่านี้
Rick James

8
ฉันไม่รู้ว่าฉันรู้สึกอย่างไรเกี่ยวกับเรื่องนี้ - แทนที่จะแก้ไขการใช้งานของพวกเขาให้เป็นไปตามมาตรฐาน Unicode ล่าสุดที่พวกเขาเก็บรุ่นล้าสมัยเป็นค่าเริ่มต้นและผู้คนต้องเพิ่ม "520" เพื่อใช้งานที่เหมาะสมในขณะนี้ และไม่รองรับการส่งต่อและไปข้างหลังเพราะคุณไม่สามารถใช้เวอร์ชัน "520" กับ MySQL รุ่นเก่าได้ เหตุใดพวกเขาจึงไม่เพิ่งอัปเดตการเปรียบเทียบที่มีอยู่ เหมือนกับ "mb4" จริงๆ รหัสใดขึ้นอยู่กับพฤติกรรมแบบเก่า จำกัด / ล้าสมัยจริง ๆ เพื่อให้เหตุผลว่าเป็นค่าเริ่มต้น
thomasrutter

7
ยังดีเป็นค่าเริ่มต้น 8.0 utf8mb4_0900_ai_ciของ
Rick James

คำตอบ:


1591

การเปรียบเทียบทั้งสองนี้เป็นทั้งการเข้ารหัสอักขระ UTF-8 ความแตกต่างอยู่ในวิธีการเรียงลำดับข้อความและเปรียบเทียบ

หมายเหตุ: ใน MySQL คุณต้องใช้มากกว่าutf8mb4 utf8พลุกพล่านutf8เป็นข้อบกพร่องของการใช้งาน UTF-8 จาก MySQL รุ่นแรกซึ่งยังคงมีเพียงความเข้ากันได้แบบย้อนหลัง utf8mb4รุ่นคงได้รับชื่อ

หมายเหตุ: MySQL เวอร์ชั่นใหม่กว่านี้ได้ปรับปรุงกฎการเรียงลำดับ Unicode ให้ใช้งานได้ภายใต้ชื่อเช่น utf8mb4_0900_ai_ci สำหรับกฎที่เทียบเท่าโดยยึดตาม Unicode 9.0 - และไม่มี _general ตัวแปรที่ เทียบเท่า คนที่อ่านข้อความนี้ในขณะนี้อาจจะใช้หนึ่งใน collations ใหม่เหล่านี้แทนการอย่างใดอย่างหนึ่งหรือ_unicode สิ่งที่เขียนไว้ด้านล่างส่วนใหญ่ไม่ได้เป็นที่สนใจอีกต่อไปหากคุณสามารถใช้หนึ่งในการเปรียบเทียบที่ใหม่กว่าแทน_general

ความแตกต่างที่สำคัญ

  • utf8mb4_unicode_ci ขึ้นอยู่กับกฎ Unicode อย่างเป็นทางการสำหรับการจัดเรียงและเปรียบเทียบสากลซึ่งเรียงลำดับอย่างถูกต้องในหลากหลายภาษา

  • utf8mb4_general_ciเป็นชุดกฎการเรียงลำดับที่เรียบง่ายซึ่งมีจุดมุ่งหมายที่จะทำเช่นเดียวกับที่ทำได้ในขณะที่ใช้ช็อตคัทจำนวนมากที่ออกแบบมาเพื่อปรับปรุงความเร็ว มันไม่เป็นไปตามกฎ Unicode และจะส่งผลให้เกิดการเรียงลำดับหรือเปรียบเทียบที่ไม่พึงประสงค์ในบางสถานการณ์เช่นเมื่อใช้ภาษาหรืออักขระบางอย่าง

    บนเซิร์ฟเวอร์ที่ทันสมัยการเพิ่มประสิทธิภาพนี้จะเป็นเพียงเล็กน้อยเท่านั้น มันถูกคิดค้นขึ้นในช่วงเวลาที่เซิร์ฟเวอร์มีประสิทธิภาพของ CPU เพียงเล็กน้อยในคอมพิวเตอร์ทุกวันนี้

ประโยชน์ของการutf8mb4_unicode_ciมากกว่าutf8mb4_general_ci

utf8mb4_unicode_ciซึ่งใช้กฎ Unicode สำหรับการเรียงลำดับและการเปรียบเทียบใช้อัลกอริทึมที่ค่อนข้างซับซ้อนสำหรับการจัดเรียงที่ถูกต้องในหลากหลายภาษาและเมื่อใช้อักขระพิเศษหลากหลายชนิด กฎเหล่านี้ต้องคำนึงถึงอนุสัญญาเฉพาะภาษา ทุกคนไม่เรียงลำดับตัวละครของพวกเขาในสิ่งที่เราจะเรียกว่า 'ลำดับตามตัวอักษร'

เท่าที่ภาษาลาติน (เช่น "ยุโรป") ไม่มีความแตกต่างระหว่างการเรียงลำดับ Unicode และการutf8mb4_general_ciเรียงลำดับแบบง่ายใน MySQL แต่ยังคงมีความแตกต่างเล็กน้อย:

  • ตัวอย่างเช่นการเรียง Unicode เรียง "ß" เช่น "ss" และ "Œ" เช่น "OE" เป็นคนที่ใช้อักขระเหล่านั้นตามปกติจะต้องการในขณะที่utf8mb4_general_ciเรียงพวกเขาเป็นอักขระเดี่ยว (สมมุติว่า "s" และ "e" ตามลำดับ) .

  • อักขระ Unicode บางตัวถูกกำหนดเป็นเพิกเฉยซึ่งหมายความว่าไม่ควรนับรวมถึงลำดับการเรียงและการเปรียบเทียบควรย้ายไปยังอักขระถัดไปแทน utf8mb4_unicode_ciจัดการเหล่านี้อย่างถูกต้อง

ในภาษาที่ไม่ใช่ภาษาละตินเช่นภาษาเอเชียหรือภาษาที่มีตัวอักษรที่แตกต่างกันอาจจะมีมากมากขึ้นความแตกต่างระหว่างการเรียงลำดับ Unicode และง่ายutf8mb4_general_ciเรียงลำดับ ความเหมาะสมของutf8mb4_general_ciจะขึ้นอยู่กับภาษาที่ใช้อย่างมาก สำหรับบางภาษามันค่อนข้างไม่เพียงพอ

คุณควรใช้อะไร

แทบจะไม่มีเหตุผลที่จะใช้utf8mb4_general_ciอีกต่อไปเพราะเราทิ้งไว้ข้างหลังจุดที่ความเร็วของ CPU ต่ำพอที่ความแตกต่างของประสิทธิภาพจะมีความสำคัญ ฐานข้อมูลของคุณจะถูก จำกัด ด้วยคอขวดอื่น ๆ อย่างแน่นอน

ในอดีตบางคนแนะนำให้ใช้utf8mb4_general_ciยกเว้นเมื่อการเรียงลำดับที่แม่นยำจะมีความสำคัญพอที่จะประเมินต้นทุนการปฏิบัติ วันนี้ค่าใช้จ่ายด้านประสิทธิภาพนั้นหายไปหมดและนักพัฒนากำลังรักษาความเป็นสากลมากขึ้น

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

สิ่งหนึ่งที่ฉันจะเพิ่มคือแม้ว่าคุณจะรู้ว่าแอปพลิเคชันของคุณสนับสนุนเฉพาะภาษาอังกฤษ แต่ก็อาจจำเป็นต้องจัดการกับชื่อของผู้คนซึ่งมักจะมีตัวอักษรที่ใช้ในภาษาอื่น ๆ . การใช้กฎ Unicode สำหรับทุกสิ่งช่วยเพิ่มความอุ่นใจว่าคน Unicode ที่ฉลาดมากทำงานหนักมากเพื่อให้การเรียงลำดับทำงานได้อย่างถูกต้อง

ชิ้นส่วนหมายถึงอะไร

ประการแรกciคือสำหรับการเรียงลำดับและการเปรียบเทียบแบบคำนึงถึงขนาดตัวพิมพ์ ซึ่งหมายความว่ามันเหมาะสำหรับข้อมูลที่เป็นข้อความและกรณีไม่สำคัญ การเปรียบเทียบประเภทอื่นคือcs( binคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) สำหรับข้อมูลต้นฉบับที่กรณีสำคัญและสำหรับการเข้ารหัสที่ต้องตรงกันบิตสำหรับบิตซึ่งเหมาะสำหรับเขตข้อมูลที่เข้ารหัสข้อมูลไบนารีจริง ๆ (รวมถึงตัวอย่างเช่น Base64) การเรียงลำดับตามตัวพิมพ์เล็กและตัวพิมพ์ใหญ่นำไปสู่ผลลัพธ์แปลก ๆ และการเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่อาจส่งผลให้ค่าซ้ำซ้อนแตกต่างกันในกรณีตัวอักษรเท่านั้นดังนั้นการเรียงตามตัวพิมพ์ใหญ่ - ตัวพิมพ์เล็ก และอาจมีความสำคัญเช่นกันและการเปรียบเทียบแบบไบนารีอาจเหมาะสมกว่า

ถัดไปunicodeหรือgeneralอ้างถึงกฎการเรียงลำดับและการเปรียบเทียบเฉพาะ - โดยเฉพาะอย่างยิ่งวิธีที่ข้อความถูกทำให้เป็นมาตรฐานหรือเปรียบเทียบ มีกฎหลายชุดสำหรับการเข้ารหัสอักขระ utf8mb4 โดยมีunicodeและgeneralเป็นสองชุดที่พยายามทำงานได้ดีในภาษาที่เป็นไปได้ทั้งหมดมากกว่าหนึ่งชุด ความแตกต่างระหว่างกฎทั้งสองชุดนี้เป็นหัวข้อของคำตอบนี้ โปรดทราบว่าunicodeใช้กฎจาก Unicode 4.0 MySQL รุ่นล่าสุดเพิ่มชุดกฎunicode_520โดยใช้กฎจาก Unicode 5.2 และ0900(วางส่วน "unicode_") โดยใช้กฎจาก Unicode 9.0

และสุดท้ายutf8mb4คือการเข้ารหัสอักขระที่ใช้ภายใน ในคำตอบนี้ฉันกำลังพูดถึงการเข้ารหัสตาม Unicode เท่านั้น


218
@KahWeeTeng คุณไม่ควรใช้เคยutf8_general_ci : มันใช้งานไม่ได้ มันเป็นการย้อนกลับไปสู่ยุคสมัยที่ไม่ดีของ ASCII ในฐานะคนเฝ้าประตูเมื่อห้าสิบปีก่อน การจับคู่แบบไม่คำนึงถึงตัวอักษรแบบ Unicode ไม่สามารถทำได้หากไม่มีแผนผังการพับจาก UCD ตัวอย่างเช่น“ Σίσυφος” มีสามซิกมาสอยู่ในนั้น หรือตัวพิมพ์เล็กของ "TSCHüẞ" คือ "tschüβ" แต่ตัวพิมพ์ใหญ่ของ "tschüβ" คือ "TSCHÜSS" คุณสามารถพูดถูกหรือเร็ว ดังนั้นคุณต้องใช้utf8_unicode_ciเพราะถ้าคุณไม่สนใจเรื่องความถูกต้องมันเป็นเรื่องไม่สำคัญที่จะทำให้มันเร็วอย่างไม่มีที่สิ้นสุด
tchrist

7
หลังจากอ่านเรื่องนี้แล้วฉันก็ค้นพบว่า utf8_unicode_ci จะพิจารณาตัวละครใด ๆ ที่มีการเปรียบเทียบน้ำหนักเท่ากันเพื่อจุดประสงค์ในการเปรียบเทียบความเท่าเทียมกัน นำไปสู่กรณีนี้ที่หรือ"か" == "が" "ǽ" == "æ"สำหรับการเรียงลำดับสิ่งนี้สมเหตุสมผล แต่อาจเป็นเรื่องที่น่าแปลกใจเมื่อเลือกผ่านอีควิตี้
Mat Schaffer

4
@DanHorvat เหตุผลเชิงปฏิบัติเพียงข้อเดียวในการ จำกัด ตัวคุณให้แก่ชุดย่อยเก่าของ Unicode ของ MySQL ที่ จำกัด มากขึ้นก็คือถ้าคุณมี MySQL รุ่นเก่าที่ไม่รองรับ utf8mb4 ที่สมบูรณ์มากขึ้น 5.5.3 อายุมากกว่า 5 ปี ฉันขอขอบคุณที่ Plesk ทำงานบนตาราง MySQL ที่แตกต่างกัน แต่ distros ส่วนใหญ่อยู่บน MySQL 5.5 ในขณะนี้และ Plesk 11.x ไม่รองรับ MySQL 5.5 หากคุณอัปเดตส่วนประกอบ
thomasrutter

22
ฉันจะไม่เห็นด้วยว่าการใช้ตัวแปรการร้องเรียนมาตรฐานที่ใหม่กว่านั้นเป็นวิธีปฏิบัติที่ไม่ดีและฉันคิดว่ามันเป็นการอักเสบที่จะเรียกผู้พัฒนาที่ไม่ดีมาทำอะไรแบบนี้ คุณอาจต้องการทราบว่าคำตอบของฉันตามที่กล่าวว่า " ใน MySQL เวอร์ชันใหม่ใช้ utf8mb4 แทนที่จะใช้ utf8"
thomasrutter

24
@DanHorvat utf8mb4เป็นทางเลือกเดียวที่ถูกต้อง เมื่อutf8คุณติดอยู่ใน MySQL-only บางตัวตัวแปร 3 ไบต์ของ UTF8 ที่เฉพาะ MySQL (และ MariaDB) เท่านั้นที่รู้ว่าต้องทำอะไร ส่วนที่เหลือของโลกจะใช้ UTF8 ซึ่งสามารถมีได้ถึง 4 ไบต์ต่อตัวละคร MySQL ที่ devs เรียกไม่ถูกเข้ารหัส homebrew ของพวกเขาutf8และไม่ทำลายกันได้ย้อนหลังตอนนี้พวกเขามีการอ้างถึง UTF8 utf8mb4จริง
Stijn de Witt

162

ฉันต้องการทราบว่าประสิทธิภาพการทำงานที่แตกต่างระหว่างการใช้งานutf8_general_ciกับอะไรutf8_unicode_ciแต่ฉันไม่พบการวัดประสิทธิภาพใด ๆ ที่ระบุไว้บนอินเทอร์เน็ตดังนั้นฉันจึงตัดสินใจสร้างการวัดประสิทธิภาพด้วยตนเอง

ฉันสร้างตารางง่าย ๆ ที่มี 500,000 แถว:

CREATE TABLE test(
  ID INT(11) DEFAULT NULL,
  Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

จากนั้นฉันก็เติมข้อมูลด้วยการสุ่มโดยรันโพรซีเดอร์นี้

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

แล้วฉันจะสร้างต่อไปนี้วิธีการจัดเก็บเพื่อมาตรฐานที่เรียบง่ายSELECT, SELECTมีLIKE, และการเรียงลำดับ ( SELECTกับ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;

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

ฉันเรียกแต่ละกระบวนงานที่เก็บไว้ 5 ครั้งสำหรับการเปรียบเทียบแต่ละครั้ง (5 ครั้งutf8_general_ciและ 5 ครั้งutf8_unicode_ci) จากนั้นคำนวณค่าเฉลี่ย

ผลลัพธ์ของฉันคือ:

benchmark_simple_select()

  • ด้วยutf8_general_ci: 9,957 ms
  • ด้วยutf8_unicode_ci: 10,271 ms

ในมาตรฐานนี้ใช้utf8_unicode_ciช้ากว่าutf8_general_ci3.2%

benchmark_select_like()

  • ด้วยutf8_general_ci: 11,441 ms
  • ด้วยutf8_unicode_ci: 12,811 ms

ในการวัดประสิทธิภาพนี้ใช้utf8_unicode_ciช้ากว่าutf8_general_ci12%

benchmark_order_by()

  • ด้วยutf8_general_ci: 11,944 ms
  • ด้วยutf8_unicode_ci: 12,887 ms

ในการวัดประสิทธิภาพนี้ใช้utf8_unicode_ciช้ากว่าutf8_general_ci7.9%


16
เกณฑ์มาตรฐานที่ดีขอบคุณสำหรับการแบ่งปัน ฉันได้รับตัวเลขที่คล้ายกันอย่างสมเหตุสมผล (MySQL v5.6.12 บน Windows): 10%, 4%, 8% ฉันเห็นด้วย: การเพิ่มประสิทธิภาพของutf8_general_ciมันน้อยเกินไปที่จะคุ้มค่าที่จะใช้
RandomSeed

10
1) แต่เกณฑ์มาตรฐานนี้ไม่ควรสร้างผลลัพธ์ที่คล้ายคลึงกันสำหรับการเปรียบเทียบทั้งสองโดยการกำหนด? ฉันหมายถึงCONV(FLOOR(RAND() * 99999999999999), 20, 36)สร้างเฉพาะ ASCII เท่านั้นและไม่มีอักขระ Unicode ที่จะดำเนินการโดยอัลกอริทึมของการเปรียบเทียบ 2) Description = 'test' COLLATE ...และDescription LIKE 'test%' COLLATE ...ประมวลผลสตริงเดียวเท่านั้น ("ทดสอบ") ตอนรันไทม์ใช่ไหม 3) ในแอปจริงคอลัมน์ที่ใช้ในการสั่งซื้ออาจจะถูกจัดทำดัชนีและความเร็วในการจัดทำดัชนีในการเปรียบเทียบที่แตกต่างกันด้วยข้อความที่ไม่ใช่ ASCII จริงอาจแตกต่างกัน
Halil Özgür

2
@ HalilÖzgür - จุดของคุณผิดพลาดบางส่วน ฉันเดาว่ามันไม่เกี่ยวกับค่า codepoint ที่จะอยู่นอก ASCII (ซึ่ง general_ci จะจัดการได้อย่างถูกต้อง) แต่เกี่ยวกับคุณสมบัติเฉพาะเช่นการรักษา umlauts ที่เขียนเป็น "Uml ea ute" หรือรายละเอียดปลีกย่อยบางอย่าง
Tomasz Gandor

38

โพสต์นี้จะอธิบายอย่างดีมาก

กล่าวโดยย่อ: utf8_unicode_ci ใช้อัลกอริทึมการจัดเรียง Unicode ตามที่กำหนดไว้ในมาตรฐาน Unicode ในขณะที่ utf8_general_ci เป็นคำสั่งการเรียงลำดับที่ง่ายขึ้นซึ่งส่งผลให้ผลลัพธ์การเรียงลำดับ "แม่นยำน้อยลง"


1
ขอบคุณ นั่นคือความประทับใจของฉัน ฉันจะแสดงที่ยอดเยี่ยม :)
onassar

7
หากคุณไม่สนใจความถูกต้องมันเป็นเรื่องไม่สำคัญที่จะทำให้อัลกอริทึมใด ๆ ทำงานได้อย่างรวดเร็ว เพียงแค่ใช้utf8_unicode_ciและแสร้งทำเป็นอีกอันหนึ่งไม่มีอยู่
tchrist

1
@tchrist แต่ถ้าคุณดูแลเกี่ยวกับความสมดุลบางอย่างระหว่างความถูกต้องและความเร็วutf8_general_ciอาจเหมาะสำหรับคุณ
Shelvacu

@tchrist ไม่เคยเป็นโปรแกรมเมอร์เกม;)
Stijn de Witt

1
@onassar - MySQL 8.0 อ้างว่ามีการปรับปรุงประสิทธิภาพของการเปรียบเทียบทั้งหมดอย่างมีนัยสำคัญ
Rick James

9

ดูคู่มือ mysql, ชุดอักขระ Unicode :

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

ดังนั้นเพื่อสรุป utf_general_ci ใช้ชุดการเปรียบเทียบที่เล็กกว่าและถูกต้อง (ตามมาตรฐาน) น้อยกว่า utf_unicode_ci ซึ่งควรใช้ทั้งมาตรฐาน ชุด general_ci จะเร็วขึ้นเนื่องจากมีการคำนวณน้อยกว่า


18
ไม่มีสิ่งเช่น "ถูกต้องน้อยกว่าเล็กน้อย" ความถูกต้องเป็นลักษณะบูลีน; มันไม่ยอมรับโมดิฟายเออร์ของดีกรี เพียงใช้utf8_unicode_ciและแสร้งทำเป็นว่ารถที่ใช้ไม่ได้
tchrist

2
ฉันมีปัญหาในการรับ 5.6.15 เพื่อทำการตั้งค่า collation_connection และปรากฎว่าคุณต้องผ่านมันในบรรทัด SET เช่น 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci' เครดิตไปที่ Mathias Bynens สำหรับการแก้ปัญหานี่คือคำแนะนำที่มีประโยชน์มากของเขา: mathiasbynens.be/notes/mysql-utf8mb4
Steve Hibbert

4
@tchrist ปัญหาเกี่ยวกับการพูดความถูกต้องคือบูลีนคือมันไม่ได้คำนึงถึงสถานการณ์ที่ไม่พึ่งพาความถูกต้องแน่นอน จุดเริ่มต้นของคุณไม่ถูกต้องหรือฉันพยายามที่จะรับผลประโยชน์จาก general_ci แต่ข้อความทั่วไปของคุณเกี่ยวกับความถูกต้องนั้นพิสูจน์หักล้างได้ง่าย ฉันทำมันทุกวันในอาชีพของฉัน ตลกกันจ๊วร์ตมีจุดดีที่นี่
แอนโธนี

5
ด้วยการระบุตำแหน่งทางภูมิศาสตร์หรือการพัฒนาเกมเราแลกเปลี่ยนความถูกต้องกับประสิทธิภาพตลอดเวลา และแน่นอนความถูกต้องเป็นจำนวนจริงระหว่าง0และ1ไม่ใช่บูล :) EG เลือกจุดทางภูมิศาสตร์ในกล่องขอบเขตเป็นการประมาณ 'จุดใกล้เคียง' ซึ่งไม่ดีเท่ากับการคำนวณระยะทางระหว่างจุดและจุดอ้างอิงและการกรองบนนั้น แต่ทั้งคู่เป็นการประมาณค่าและในความเป็นจริงความถูกต้องทั้งหมดนั้นไม่สามารถทำได้ ดูเส้นขนานที่ชายฝั่งและIEEE 754
Stijn de Witt

4
TL; DR : โปรดระบุโปรแกรมที่พิมพ์ผลลัพธ์ที่ถูกต้องสำหรับ1/3
Stijn de Witt

7

กล่าวโดยย่อ:

หากคุณต้องการลำดับการเรียงที่ดีกว่า - ใช้utf8_unicode_ci(นี่เป็นวิธีที่ต้องการ)

แต่ถ้าคุณสนใจประสิทธิภาพการทำงานอย่างเต็มที่ - ใช้งานutf8_general_ciแต่รู้ว่ามันล้าสมัยไปเล็กน้อย

ความแตกต่างในแง่ของประสิทธิภาพมีน้อยมาก


1
ทั้งคู่ล้าสมัยแล้ว - ดูคำตอบที่ยอมรับได้มากขึ้น
thomasrutter

ตกลงขอบคุณ
@thomasrutter

6

รายละเอียดบางอย่าง (PL)

ในขณะที่เราสามารถอ่านได้ที่นี่ ( Peter Gulutzan ) มีความแตกต่างในการเรียงลำดับ / การเปรียบเทียบตัวอักษรโปแลนด์ "Ł" (L กับโรคหลอดเลือดสมอง - html esc:) Ł(กรณีที่ต่ำกว่า: "ł" - html esc:) ł- เรามีสมมติฐานดังนี้

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

ในจดหมายฉบับภาษาโปแลนด์Łคือหลังจากที่ตัวอักษรและก่อนที่L Mไม่มีการเข้ารหัสใดที่ดีกว่าหรือแย่กว่านี้ขึ้นอยู่กับความต้องการของคุณ


1

การเรียงลำดับและการจับคู่อักขระมีความแตกต่างใหญ่สองอย่าง:

เรียงลำดับ :

  • utf8mb4_general_ci ลบสำเนียงทั้งหมดและเรียงลำดับทีละรายการซึ่งอาจสร้างผลลัพธ์การเรียงลำดับที่ไม่ถูกต้อง
  • utf8mb4_unicode_ci เรียงลำดับที่ถูกต้อง

การจับคู่ตัวละคร

พวกเขาจับคู่ตัวละครแตกต่างกัน

ยกตัวอย่างเช่นในutf8mb4_unicode_ciคุณมีi != ıแต่มันถือutf8mb4_general_ciı=i

name="Yılmaz"ตัวอย่างเช่นสมมติคุณมีแถวด้วย แล้วก็

select id from users where name='Yilmaz';

จะส่งคืนแถวหากการจัดวางเป็นutf8mb4_general_ciแต่ถ้าเป็นการจัดวางด้วยutf8mb4_unicode_ciจะไม่ส่งคืนแถว!

บนมืออื่น ๆ ที่เรามีที่a=ªและß=ssในซึ่งเป็นกรณีที่ไม่อยู่ในutf8mb4_unicode_ci utf8mb4_general_ciดังนั้นลองจินตนาการว่าคุณมีแถวอยู่name="ªßi"แล้ว

select id from users where name='assi';

จะกลับมาแถวถ้าการจัดระเบียบเป็นutf8mb4_unicode_ciแต่จะไม่ได้utf8mb4_general_ciกลับมาแถวจัดระเบียบถ้ามีการตั้งค่า

รายการเต็มรูปแบบของการแข่งขันในแต่ละการจัดระเบียบอาจจะพบได้ที่นี่


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