การเปรียบเทียบแบบ case-insensitive ทำงานอย่างไร


19

ชนิดการเรียงข้อมูลเริ่มต้นใน SQL Server อนุญาตสำหรับการทำดัชนีกับสตริงที่ไม่คำนึงถึงขนาดตัวพิมพ์ แต่เคสของข้อมูลยังคงอยู่ มันใช้งานได้จริงอย่างไร? ฉันกำลังมองหาถั่วและโบลต์บิตและไบต์จริง ๆ หรือแหล่งข้อมูลที่ดีที่อธิบายรายละเอียด

create table casetest (fruitnames nvarchar(50) not null);
create unique index IX_fruitnames on casetest(fruitnames);

insert into casetest values ('apples');
insert into casetest values ('Pears');
-- this insert fails
insert into casetest values ('pears');

-- this yields 'Pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

update casetest set fruitnames = 'pears' where fruitnames = 'pEArs'

-- this yields 'pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

คำถามเกี่ยวกับการเปรียบเทียบของ SQL Server ที่คุณอายเกินกว่าจะถามโดย Robert Sheldon ครอบคลุมวิธีการใช้ collation มันไม่ครอบคลุมถึงวิธีการเปรียบเทียบการทำงาน ฉันสนใจว่าดัชนีสามารถสร้างได้อย่างมีประสิทธิภาพ / สอบถามไม่สนใจกรณีและในขณะที่การจัดเก็บข้อมูลกรณี


1
คุณสามารถแบบสอบถามได้อย่างมีประสิทธิภาพ (เช่นการใช้ดัชนีแสวงหา) สตริงกรณีตายกับสนามเป็นกรณี ๆ ไป แต่ก็เพียงเล็กน้อยที่น่ารำคาญ
จอห์น Eisbrener

cocogorilla: โปรดดูหมายเหตุ # 1 ที่ฉันเพิ่งเพิ่มในตอนท้ายของคำตอบของฉันอีกครั้ง: การเปรียบเทียบ "เริ่มต้น"
โซโลมอน Rutzky

คำตอบ:


26

การจัดทำดัชนีกับสตริงที่ไม่คำนึงถึงขนาดตัวพิมพ์ แต่เคสของข้อมูลยังคงอยู่ มันใช้งานได้จริงอย่างไร?

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

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

ข้อมูลทั้งในตาราง / ดัชนีคลัสเตอร์หรือดัชนีที่ไม่ใช่คลัสเตอร์ไม่ได้มีการตรวจทาน / ข้อมูลใด ๆ เรียงลำดับ มันเป็นเพียงข้อมูล การจัดเรียง (โลแคล / กฎของวัฒนธรรมและความไว) เป็นเพียงข้อมูลเมตาที่แนบมากับคอลัมน์และใช้เมื่อเรียกใช้การดำเนินการเรียงลำดับ (เว้นแต่จะถูกแทนที่โดยCOLLATEข้อ) ซึ่งจะรวมถึงการสร้าง / สร้างใหม่ของดัชนี กฎที่กำหนดโดยการเปรียบเทียบที่ไม่ใช่ไบนารีถูกใช้เพื่อสร้างการเรียงลำดับคีย์ซึ่งเป็นการแทนไบนารีของสตริง (คีย์การเรียงลำดับไม่จำเป็นในการเปรียบเทียบไบนารี) การเป็นตัวแทนไบนารีเหล่านี้รวมกฎของโลแคล / วัฒนธรรมและความไวที่เลือกไว้ทั้งหมด การเรียงลำดับคีย์ถูกใช้เพื่อวางเร็กคอร์ดในลำดับที่เหมาะสม แต่จะไม่ถูกเก็บไว้ในดัชนีหรือตาราง พวกเขาจะไม่ถูกเก็บไว้ (อย่างน้อยฉันไม่ได้เห็นค่าเหล่านี้ในดัชนีและบอกว่าพวกเขาไม่ได้เก็บไว้) เพราะ:

  1. พวกเขาไม่จำเป็นต้องเรียงลำดับอย่างแท้จริงเพราะพวกเขาจะอยู่ในลำดับเดียวกับแถวในตารางหรือดัชนีอย่างไรก็ตาม แต่ลำดับทางกายภาพของดัชนีเป็นเพียงการเรียงลำดับไม่ใช่การเปรียบเทียบ
  2. ในขณะที่การจัดเก็บอาจทำให้การเปรียบเทียบเร็วขึ้น แต่ก็จะทำให้ดัชนีมีขนาดใหญ่ขึ้นเนื่องจากขนาดต่ำสุดสำหรับอักขระตัวเดียวคือ 5 ไบต์และนั่นเป็นเพียง "ค่าใช้จ่าย" (ของโครงสร้างคีย์การเรียงลำดับ) อักขระส่วนใหญ่มีขนาด 2 ไบต์และอีก 1 ไบต์หากมีการเน้นเสียงและอีก 1 ไบต์หากเป็นตัวพิมพ์ใหญ่ ตัวอย่างเช่น "e" เป็นคีย์ขนาด 7 ไบต์ "E" และ "é" มีทั้ง 8 ไบต์และ "É" เป็นคีย์ขนาด 9 ไบต์ ดังนั้นอย่าเก็บสิ่งเหล่านี้ไว้ในที่สุด

การเปรียบเทียบมีสองประเภท: SQL Server และ Windows

เซิร์ฟเวอร์ SQL

การเปรียบเทียบ SQL Server (ชื่อที่ขึ้นต้นด้วยSQL_) เป็นวิธีการเรียงลำดับ / เปรียบเทียบก่อนหน้าของ SQL Server 2000 (แม้ว่าSQL_Latin1_General_CP1_CI_ASจะยังคงเป็นค่าเริ่มต้นในการติดตั้งบนระบบปฏิบัติการภาษาอังกฤษของสหรัฐฯ ในรูปแบบเก่าที่เรียบง่ายไม่ใช่ยูนิโคดการรวมกันของสถานที่เกิดเหตุหน้ารหัสและความไวต่างๆจะได้รับการทำแผนที่แบบคงที่ของตัวละครแต่ละตัวในหน้ารหัสที่ อักขระแต่ละตัวได้รับการกำหนดค่า (เช่นน้ำหนักการเรียงลำดับ) เพื่อแสดงว่ามันมีความสอดคล้องกับอักขระอื่นอย่างไร การเปรียบเทียบในรุ่นนี้ดูเหมือนจะเป็นการดำเนินการสองรอบ:

  1. ก่อนอื่นมันจะกำจัดสำเนียงทั้งหมด (เช่น "  ü  " กลายเป็น "  u  ") ขยายตัวอักขระเช่น "  Æ  " เป็น "  A  " และ "  E  " จากนั้นทำการเรียงลำดับเริ่มต้นเพื่อให้คำเรียงตามลำดับตามธรรมชาติ คาดว่าจะพบพวกเขาในพจนานุกรม)
  2. จากนั้นมันจะไปตามตัวอักษรเพื่อกำหนดความเท่าเทียมกันตามค่าพื้นฐานเหล่านี้ต่อตัวละครแต่ละตัว นี้ส่วนที่สองคือสิ่งที่ mustaccio จะอธิบายในคำตอบของเขา

ความไวต่อแสงเพียงอย่างเดียวที่สามารถปรับได้ในการเปรียบเทียบนี้คือ: "ตัวพิมพ์ใหญ่" และ "เน้น" ("ความกว้าง", "ประเภทคะนะ" และ "ตัวเลือกชุดรูปแบบ" ไม่พร้อมใช้งาน) นอกจากนี้ยังไม่มีการเปรียบเทียบเหล่านี้ที่สนับสนุนอักขระเพิ่มเติม (ซึ่งสมเหตุสมผลว่าเป็น Unicode เฉพาะและการเปรียบเทียบเหล่านี้ใช้กับข้อมูลที่ไม่ใช่ Unicode เท่านั้น)

วิธีการนี้ใช้เพียงเพื่อที่ไม่ใช่ Unicode VARCHARข้อมูล การผสมผสานที่ไม่ซ้ำกันของสถานที่, รหัสหน้า, ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ - เสียงเน้นเสียงมี "รหัสการเรียงลำดับ" เฉพาะซึ่งคุณสามารถดูได้ในตัวอย่างต่อไปนี้:

SELECT COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CI_AS', 'SortID'), -- 52
       COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CS_AS', 'SortID'), -- 51
       COLLATIONPROPERTY(N'Latin1_General_100_CI_AS',     'SortID'); --  0

ข้อแตกต่างระหว่างการเปรียบเทียบสองครั้งแรกคือการพิจารณาตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ การเปรียบเทียบที่สามคือการเปรียบเทียบ Windows และดังนั้นจึงไม่มีตารางการแมปแบบคงที่

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

ของ windows

การจัดเรียง Windows (ชื่อที่ไม่ได้ขึ้นต้นด้วยSQL_) เป็นวิธีการเรียงลำดับ / การเปรียบเทียบที่ใหม่กว่า (เริ่มต้นใน SQL Server 2000) ในโมเดล Unicode ที่ใหม่กว่าซับซ้อนนี้การรวมกันของสถานที่เกิดเหตุแต่ละหน้ารหัสและความไวที่แตกต่างกันจะไม่ได้รับการทำแผนที่แบบคงที่ สิ่งหนึ่งที่ไม่มีรหัสหน้าในรุ่นนี้ รุ่นนี้กำหนดค่าการเรียงเริ่มต้นให้กับแต่ละอักขระจากนั้นแต่ละโลแคล / วัฒนธรรมสามารถกำหนดค่าการเรียงใหม่ให้กับจำนวนอักขระได้ สิ่งนี้ทำให้หลายวัฒนธรรมสามารถใช้อักขระเดียวกันในวิธีที่ต่างกัน สิ่งนี้มีผลต่อการอนุญาตให้เรียงหลายภาษาโดยธรรมชาติโดยใช้การเรียงเดียวกันหากไม่ใช้อักขระเดียวกัน (และหากหนึ่งในนั้นไม่จำเป็นต้องกำหนดค่าใหม่อีกครั้งและสามารถใช้ค่าเริ่มต้นได้)

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

การเปรียบเทียบในรุ่นนี้เป็นการทำงานแบบมัลติพาส:

  1. ก่อนอื่นสตริงจะถูกทำให้เป็นมาตรฐานเพื่อให้วิธีที่หลากหลายในการแสดงอักขระเดียวกันจะถือเอา ตัวอย่างเช่น " ü " อาจเป็นอักขระ / จุดรหัสเดียว (U + 00FC) คุณสามารถรวม " u " ที่ไม่เน้นเสียงได้(U + 0075) เข้ากับการรวมการรวม " ̈ " (U + 0308) เพื่อรับ: " ü " ซึ่งไม่เพียง แต่ดูเหมือนจะเหมือนกันเมื่อเรนเดอร์ (เว้นแต่มีปัญหากับ แบบอักษรของคุณ) แต่ก็ถือว่าเหมือนกันกับเวอร์ชันอักขระตัวเดียว (U + 00FC) ยกเว้นว่าใช้การเปรียบเทียบแบบไบนารี (ซึ่งเปรียบเทียบไบต์แทนอักขระ) การนอร์มัลไลซ์เซชั่นแบ่งอักขระเดี่ยวออกเป็นส่วนต่าง ๆ ซึ่งรวมถึงการขยายสำหรับอักขระเช่น "  Æ  " (ดังที่ระบุไว้ข้างต้นสำหรับการเปรียบเทียบของ SQL Server)
  2. การดำเนินการเปรียบเทียบในรุ่นนี้จะมีตัวอักษรต่ออักขระตามความไวแต่ละตัว คีย์การเรียงลำดับสำหรับสตริงจะถูกกำหนดโดยการใช้องค์ประกอบที่เหมาะสมของแต่ละอาร์เรย์เรียงตัวอักษรของค่าตามความไวที่ "ไว" ค่าคีย์การเรียงลำดับจะถูกจัดเรียงโดยความไวหลักทั้งหมดของอักขระแต่ละตัว (อักขระพื้นฐาน) ตามด้วยความไวแสงรองทั้งหมด (น้ำหนักกำกับน้ำหนัก) ตามด้วยน้ำหนักตัวพิมพ์ของแต่ละอักขระและอื่น ๆ
  3. การเรียงลำดับจะดำเนินการตามคีย์การเรียงลำดับที่คำนวณได้ ด้วยความไวแต่ละอย่างที่จัดกลุ่มไว้ด้วยกันคุณจะได้รับการเรียงลำดับที่แตกต่างจากการเปรียบเทียบ SQL Server ที่เทียบเท่ากันเมื่อเปรียบเทียบสตริงของอักขระหลายตัวและมีการเน้นเสียงที่เกี่ยวข้องและการเปรียบเทียบนั้นมีความอ่อนไหวต่อสำเนียง ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่)

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการเรียงลำดับนี้ในที่สุดฉันจะเผยแพร่โพสต์ที่แสดงค่าคีย์การเรียงลำดับวิธีการคำนวณความแตกต่างระหว่างการเรียง SQL Server และ Windows เป็นต้น แต่สำหรับตอนนี้โปรดดูคำตอบของฉัน: Accent Sensitive Sort ( โปรดทราบว่าคำตอบอื่น ๆ สำหรับคำถามนั้นเป็นคำอธิบายที่ดีของอัลกอริทึม Unicode อย่างเป็นทางการ แต่ SQL Server ใช้การกำหนดเองแทนแม้ว่าจะคล้ายกันอัลกอริทึมและแม้แต่ตารางน้ำหนักแบบกำหนดเอง)

ความไวแสงทั้งหมดสามารถปรับได้ในการจัดเรียงเหล่านี้: "case", "accent", "width", "kana type" และ "select selector" (เริ่มใน SQL Server 2017 และสำหรับ Collation ญี่ปุ่นเท่านั้น) นอกจากนี้การเปรียบเทียบเหล่านี้บางส่วน (เมื่อใช้กับข้อมูล Unicode) สนับสนุนอักขระเพิ่มเติม (เริ่มต้นใน SQL Server 2012) วิธีการนี้ใช้กับทั้งสองNVARCHAR และ VARCHARข้อมูล (แม้แต่ข้อมูลที่ไม่ใช่ Unicode) มันใช้กับข้อมูลที่ไม่ใช่ Unicode VARCHARโดยการแปลงค่าเป็น Unicode ภายในก่อนจากนั้นจึงใช้กฎการเรียงลำดับ / การเปรียบเทียบ


โปรดทราบ:

  1. ไม่มีการเปรียบเทียบค่าเริ่มต้นสากลสำหรับ SQL Server มีค่าเริ่มต้นการติดตั้งซึ่งแตกต่างกันไปตามการตั้งค่าภาษา / ภาษาปัจจุบันของระบบปฏิบัติการ ณ เวลาที่ทำการติดตั้ง (ซึ่งน่าเสียดายSQL_Latin1_General_CP1_CI_ASสำหรับระบบภาษาอังกฤษของสหรัฐอเมริกาดังนั้นโปรดลงคะแนนสำหรับคำแนะนำนี้ ) สิ่งนี้สามารถเปลี่ยนแปลงได้ระหว่างการติดตั้ง การเปรียบเทียบระดับอินสแตนซ์นี้จากนั้นตั้งค่าการเรียงสำหรับ[model]ฐานข้อมูลซึ่งเป็นเทมเพลตที่ใช้เมื่อสร้างฐานข้อมูลใหม่ แต่การเปรียบเทียบสามารถเปลี่ยนแปลงได้เมื่อดำเนินการCREATE DATABASEโดยการระบุCOLLATEข้อ การเปรียบเทียบระดับฐานข้อมูลนี้ใช้สำหรับตัวแปรและตัวอักษรสตริงเช่นเดียวกับค่าเริ่มต้นสำหรับคอลัมน์ใหม่ (และเปลี่ยนแปลง!) เมื่อCOLLATEไม่ได้ระบุอนุประโยค (ซึ่งเป็นกรณีสำหรับรหัสตัวอย่างในคำถาม)
  2. สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Collations / encodings / Unicode โปรดไปที่: Collations Info

5

โดยทั่วไปสิ่งนี้จะถูกนำมาใช้โดยใช้ตารางเปรียบเทียบที่กำหนดคะแนนให้กับตัวละครแต่ละตัว รูทีนการเรียงลำดับมีตัวเปรียบเทียบที่ใช้ตารางที่เหมาะสมไม่ว่าจะเป็นค่าเริ่มต้นหรือที่ระบุไว้อย่างชัดเจนเพื่อเปรียบเทียบสตริงอักขระทีละอักขระโดยใช้คะแนนการเปรียบเทียบ ตัวอย่างเช่นหากตารางเปรียบเทียบนั้นกำหนดคะแนน 1 ถึง "a" และ 201 ถึง "A" และคะแนนที่ต่ำกว่าในการใช้งานเฉพาะนี้หมายถึงความสำคัญที่สูงกว่าดังนั้น "a" จะเรียงลำดับก่อนหน้า "A" ตารางอื่นอาจกำหนดคะแนนย้อนกลับ: 201 ถึง "a" และ 1 ถึง "A" และลำดับการเรียงจะย้อนกลับในภายหลัง อีกโต๊ะหนึ่งอาจกำหนดคะแนนที่เท่ากันให้กับ "a", "A", "Á" และ "Å" ซึ่งจะนำไปสู่การเปรียบเทียบและการเรียงลำดับตัวพิมพ์เล็กและตัวพิมพ์ใหญ่

ในทำนองเดียวกันตัวเปรียบเทียบแบบอิงตารางเปรียบเทียบที่ใช้เมื่อเปรียบเทียบคีย์ดัชนีกับค่าที่ระบุในเพรดิเคต


1
เพียงแค่ FYI: ข้อมูลนี้ถูกต้องในแง่ของการใช้การเปรียบเทียบของ SQL Server เท่านั้น (เช่นชื่อที่ขึ้นต้นด้วยSQL_) เมื่อใช้กับVARCHARข้อมูล สิ่งนี้ไม่เป็นความจริงอย่างแน่นอนสำหรับNVARCHARข้อมูลหรือVARCHARข้อมูลเมื่อใช้การเปรียบเทียบ Windows (ชื่อที่ไม่ได้ขึ้นต้นด้วยSQL_)
โซโลมอน Rutzky
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.