วิธีเลือกการเปรียบเทียบสำหรับฐานข้อมูลสากล?


22

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

SELECT a < b COLLATE "de_DE" FROM test1;

สมมติว่านี่เป็นวิธีที่ถูกต้องในการทำงานกับข้อมูลระหว่างประเทศซึ่งเป็นการเปรียบเทียบที่ดีที่สุดสำหรับฐานข้อมูลตัวเอง? เอกสาร PostgreSQL บอกว่า :

การเปรียบเทียบทั้ง C และ POSIX ระบุพฤติกรรม "ดั้งเดิม C" ซึ่งมีเพียงตัวอักษร ASCII "A" ถึง "Z" เท่านั้นที่จะถือว่าเป็นตัวอักษรและการเรียงลำดับจะกระทำอย่างเคร่งครัดโดยค่าไบต์รหัสตัวอักษร

ฉันคิดว่านี่เป็นตัวเลือกที่ดีที่สุดในกรณีนี้หรือฉันผิด

(คำถามโบนัส: มันช้าเกินไปที่จะเลือกการเรียงในแบบสอบถามหรือไม่)


2
จุดปวดที่ใหญ่ที่สุดที่คุณจะต้องทนทุกข์ทรมานคือในฐานข้อมูลหลายภาษาคุณต้องมีดัชนีจำนวนมากเนื่องจากดัชนีของข้อความทำให้พองได้นั้นเป็นแบบเฉพาะสำหรับการเปรียบเทียบ หากคุณมีแนวโน้มที่จะค้นหาเฉพาะภายในการเปรียบเทียบ / ภาษาคุณสามารถใช้ดัชนีบางส่วนเพื่อช่วยรักษาขนาดดัชนีภายใต้การควบคุม
Craig Ringer

2
เมื่ออ้างถึงแหล่งที่มาให้เพิ่มลิงค์
Erwin Brandstetter

คำตอบ:


27

การCเปรียบเทียบเป็นตัวเลือกที่เหมาะสม

ทุกอย่างเร็วขึ้นเล็กน้อยหากไม่มีโลแคล และเนื่องจากไม่มีการเปรียบเทียบล่ะค่ะที่เหมาะสมในการสร้างฐานข้อมูลโดยไม่ต้องCเปรียบเทียบความหมายกับ

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

โปรดทราบว่า Postgres จะสร้างบนการตั้งค่าภาษาที่ระบบปฏิบัติการพื้นฐานกำหนดไว้ดังนั้นคุณต้องสร้างสถานที่เพื่อให้แต่ละสถานที่ใช้งาน เพิ่มเติมในคำตอบที่เกี่ยวข้องในดังนั้นที่นี่และที่นี่

แต่เป็น@Craig กล่าวแล้ว , ดัชนีเป็นคอขวดในสถานการณ์นี้ การเปรียบเทียบของดัชนีจะต้องตรงกับการเปรียบเทียบของโอเปอเรเตอร์ที่ใช้ในหลายกรณีที่เกี่ยวข้องกับข้อมูลอักขระ

คุณสามารถใช้ตัวCOLLATEระบุในดัชนีเพื่อสร้างดัชนีที่ตรงกัน ดัชนีบางส่วนอาจเป็นตัวเลือกที่สมบูรณ์แบบหากคุณกำลังผสมข้อมูลในตารางเดียวกัน

ตัวอย่างเช่นตารางที่มีสตริงสากล:

CREATE TABLE string (
   string_id serial
  ,lang_id   int NOT NULL
  ,string    text NOT NULL
);

และคุณมักจะสนใจภาษาเดียวในแต่ละครั้ง:

SELECT *
FROM   string
WHERE  lang_id = 5  -- 5 being German / Germany here
AND    string > 'foo' COLLATE "de_DE"
ORDER  BY string COLLATE "de_DE";

จากนั้นสร้างดัชนีบางส่วนเช่น:

CREATE INDEX string_string_lang_id_idx ON string (string COLLATE "de_DE")
WHERE lang_id = 5;

หนึ่งภาษาสำหรับแต่ละภาษาที่คุณต้องการ

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


1
คุณใช้โลแคล C (หรือ 'ไม่ใช่โลแคล' เพื่อให้แม่นยำ) โดยค่าเริ่มต้นสำหรับฐานข้อมูลใหม่หรือไม่?
แจ็คดักลาส

1
@ JackDouglas: ไม่ฉันจะทำเพื่อกรณีพิเศษเท่านั้น โดยทั่วไปแล้วการทำงานกับสถานที่ที่ใช้โดยทั่วไปนั้นมีประโยชน์มากกว่า
Erwin Brandstetter

13

ฉันขอแนะนำให้คุณเลือกการเรียงที่ให้การสั่งซื้อ Unicode เริ่มต้น ด้วยวิธีนี้คุณจะได้รับผลลัพธ์ที่มีสติแม้ว่าคุณจะไม่แทนที่การเปรียบเทียบในแต่ละแบบสอบถาม แต่น่าเสียดายที่ระบบปฏิบัติการส่วนใหญ่ (ทั้งหมด?) ไม่มีสถานที่ซึ่งเรียกว่า "Unicode เริ่มต้น" หรืออะไรทำนองนั้นดังนั้นคุณจะต้องเดาและ / หรือทำการวิจัยทางเลือกที่ดี ตัวอย่างเช่นบน Linux / glibc โลแคล de_DE.utf8 หรือ en_US.utf8 จะส่งผ่านพฤติกรรมเริ่มต้นดังนั้นทั้งคู่จึงเป็นตัวเลือกที่ดี

ฉันไม่คิดว่าการใช้โลแคล C เป็นความคิดที่ดีเพราะพฤติกรรมเริ่มต้นของแอปพลิเคชันของคุณจะไร้ประโยชน์ และคุณอาจไม่ได้รับพฤติกรรมที่เหมาะสมจากการดำเนินการแปลงกรณี

(การแทนที่การเรียงในแบบสอบถามมีค่าใช้จ่ายไม่มากมันเป็นเพียงการแยกวิเคราะห์เวลา)


อาจจะเจ็บปวดน้อยลงที่จะมีการเริ่มต้นมีสติ ..
เออร์วิน Brandstetter

1
ขณะนี้ฉันกำลังใช้ es_CL.utf8 ในฐานข้อมูลการทดสอบ แต่ต้องขอบคุณคำตอบของคุณผมมองนิด ๆ หน่อย ๆ และพบว่าเป็นวิธีที่จะไปutf8_unicode_ci
Tae

0

เราใช้ postgres ใน container docker ดังนั้นเราจึงมี ICU ให้บริการอยู่เสมอและใช้und-x-icuเป็นค่าเริ่มต้น

สิ่งนี้ถูกกล่าวถึงในบทที่23.2.2.2.2 การเปรียบเทียบ ICUของเอกสาร postres กล่าวถึง:

und-x-icu (สำหรับ“ undefined”) การเปรียบเทียบ
ICU“ root” ใช้สิ่งนี้เพื่อรับลำดับการจัดเรียงที่ไม่เชื่อเรื่องภาษา

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