ฉันควรเพิ่มฟิลด์การเพิ่ม / ตัวตนอัตโนมัติลงในตารางตัวอ้างอิงโยงเพื่อวัตถุประสงค์ในการ PK หรือไม่


9

ฉันเพิ่มตารางการอ้างอิงโยงต่อไปนี้ในฐานข้อมูลที่โฮสต์บน SQL Server ของฉัน:

company_id bigint not null (FK)
org_path nvarchar (2048) not null

company_idข้อมูลหมายถึงidข้อมูลในตารางอื่น (ซึ่งมันเป็นคีย์หลัก)

ระบุว่ายังสามารถมีได้หลายระเบียนด้วยเหมือนกัน company_idคีย์หลักใด ๆ จะต้องใช้ทั้งสองเขตข้อมูล อย่างไรก็ตามฉันไม่สามารถสร้างคีย์โดยใช้ทั้งสองฟิลด์ได้เนื่องจากorg_pathSQL Server ยาวเกินไป

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

ฉันคาดหวังว่าจำนวนแถวทั้งหมดจะอยู่ในพันต่ำ

นอกจากนี้สาเหตุที่nvarchar (2048)เป็นเพราะค่าต้องเลียนแบบในฐานข้อมูลบุคคลที่สาม ตัวอย่างทั่วไปจะเป็นสิ่งที่ต้องการ

\Translation Providers\[customer name]\[order name]\

และสามารถมีกำกับได้

ดังนั้นคำถามของฉันคือ: มันจะมีประสิทธิภาพมากขึ้นในการเพิ่มidเขตข้อมูลการเพิ่มอัตโนมัติและใช้ร่วมกับcompany_idเป็นคีย์หลักหรือมันจะเพิ่มค่าใช้จ่ายที่ไม่จำเป็น - และความจริงที่ว่าcompany_idเป็นคีย์หลักในตารางอื่นมี ผลที่นี่?

คำตอบ:


7

สำหรับดัชนีคลัสเตอร์ที่ไม่ซ้ำกันโดยcomany_idลำพัง SQL Server จะเพิ่มตัวระบุจำนวนเต็ม 4 ไบต์ให้ซ้ำโดยอัตโนมัติ (เช่นที่สองและที่ตามมาสำหรับค่าคีย์) คีย์ดัชนีคลัสเตอร์ที่ทำซ้ำกัน นี้ไม่ได้สัมผัสกับผู้ใช้ว่า

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

นอกจากนี้หากคุณลงท้ายด้วยรายการที่ซ้ำกันการ(company_id,org_path)มีคอลัมน์ข้อมูลประจำตัวที่ชัดเจน (ประเภท "ตัวระบุที่เปิดเผย") จะช่วยให้คุณกำหนดเป้าหมายได้ง่ายขึ้นเพียงรายการใดรายการหนึ่งสำหรับการลบหรืออัปเดต


12

สิ่งหนึ่งที่ควรพิจารณาคือคีย์หลักและดัชนีแบบคลัสเตอร์นั้นไม่เหมือนกัน คีย์หลักเป็นข้อ จำกัด และจัดการกับกฎที่ข้อมูลมีชีวิตอยู่ (เช่นความสมบูรณ์ของข้อมูล); มันไม่มีส่วนเกี่ยวข้องกับประสิทธิภาพ / ประสิทธิภาพ คีย์หลักกำหนดให้คอลัมน์คีย์ต้องไม่ซ้ำกัน (รวมกัน) และไม่เป็นโมฆะ (แยกกัน) มีการบังคับใช้ PK ผ่านดัชนีที่ไม่ซ้ำแม้ว่ามันจะเป็นแบบคลัสเตอร์หรือแบบไม่เป็นคลัสเตอร์ก็ได้

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

ดังนั้นคำถามหลักของ:

มันจะมีประสิทธิภาพมากขึ้นในการเพิ่มidเขตข้อมูลที่เพิ่มขึ้นอัตโนมัติและใช้งานร่วมกับcompany_idเป็นคีย์หลักหรือจะเพิ่มค่าใช้จ่ายที่ไม่จำเป็น

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

ควรมีการIDENTITYเพิ่มคอลัมน์หรือจะเป็นค่าใช้จ่ายที่ไม่จำเป็นหรือไม่?

หากคุณเพิ่มINT IDENTITYคอลัมน์และใช้เพื่อสร้าง PK สมมติว่ามันเป็น Clustered PK ซึ่งเพิ่ม 4 ไบต์ให้กับทุกแถว คอลัมน์นี้สามารถมองเห็นได้และใช้งานได้ในแบบสอบถาม มันจะถูกเพิ่มเข้าไปในตารางอื่น ๆ เป็นสำคัญต่างประเทศ แต่ในกรณีนี้โดยเฉพาะว่าจะไม่เกิดขึ้น

หากคุณไม่เพิ่มINT IDENTITYคอลัมน์คุณจะไม่สามารถสร้าง PK ในตารางนี้ อย่างไรก็ตามคุณยังสามารถสร้างดัชนีแบบกลุ่มบนตารางได้ตราบใดที่คุณไม่ได้ใช้UNIQUEตัวเลือก ในกรณีนี้ SQL Server จะเพิ่มคอลัมน์ที่ซ่อนอยู่ซึ่งเรียกว่า "uniquifier" ซึ่งจะทำงานตามที่อธิบายไว้ข้างต้น เนื่องจากคอลัมน์ถูกซ่อนอยู่จึงไม่สามารถใช้ในการสืบค้นหรือใช้เป็นข้อมูลอ้างอิงสำหรับ Foreign Keys

เท่าที่มีประสิทธิภาพไปตัวเลือกเหล่านี้จะเหมือนกัน ใช่จะมีพื้นที่น้อยกว่าเล็กน้อยโดยมีดัชนีที่ไม่ซ้ำกันอันเนื่องมาจากบางแถว (แถวที่มีค่าคีย์เฉพาะเริ่มต้น) รับ 0 ไบต์ในขณะที่แถวทั้งหมดในIDENTITY/ PK จะใช้ 4 ไบต์ แต่จะมีแถว 0 ไบต์ไม่เพียงพอ (โดยเฉพาะอย่างยิ่งเมื่อมีจำนวนแถวน้อย) ที่จะสังเกตเห็นความแตกต่างได้โดยไม่คำนึงถึงความสะดวกในการใช้IDคอลัมน์ในแบบสอบถาม

INT IDENTITY คอลัมน์หรือแฮชของorg_pathคอลัมน์ที่คำนวณแล้วหรือไม่

ระบุว่าคุณจะไม่ต้องค้นหาแถวตามorg_pathค่าดังนั้นจึงไม่เหมาะสมที่จะเพิ่มค่าใช้จ่ายของคอลัมน์ที่คำนวณแล้วรวมถึงต้องคำนวณแฮชนั้นในแบบสอบถามเพื่อให้ตรงกับคอลัมน์ที่คำนวณ (นี่คือของฉัน ข้อเสนอแนะดั้งเดิมมีอยู่ในประวัติการแก้ไขที่นี่ซึ่งมีพื้นฐานมาจากถ้อยคำ / รายละเอียดของคำถาม) ในกรณีนี้INT IDENTITYคอลัมน์ "ID" น่าจะดีที่สุด

สั่งซื้อคอลัมน์คีย์

ระบุว่าIDคอลัมน์จะไม่ค่อยถูกใช้ในการสืบค้นและให้ที่หลักสองกรณีการใช้งานจะได้รับทั้ง "แถวทั้งหมด" หรือ "แถวทั้งหมดสำหรับการรับcompany_id" ผมจะสร้าง PK company_id, idบน และเนื่องจากนี่หมายความว่าแถวไม่ได้แทรกตามลำดับฉันจะระบุFILLFACTOR90 ของคุณจะต้องตรวจสอบให้แน่ใจว่าได้ทำการบำรุงรักษาดัชนีปกติเพื่อลดการกระจายตัว

คำถามที่สอง

ความจริงที่ว่า company_id เป็นคีย์หลักในตารางอื่นมีผลกระทบใด ๆ ที่นี่

เลขที่

ไก

เนื่องจากorg_pathค่าภายใน a company_idไม่ซ้ำกันคุณจึงควรสร้าง Trigger on INSERT, UPDATEเพื่อบังคับใช้ ในไกทำIF EXISTSแบบสอบถามที่อาจจะไม่ได้และCOUNT(*) GROUP BY company_id, org_pathหากพบสิ่งใดให้ออกROLLBACKเพื่อยกเลิกการดำเนินการ DML แล้วRAISERRORแจ้งว่ามีการทำซ้ำ

การตรวจทาน

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


ขอให้เรายังคงอภิปรายนี้ในการแชท
โซโลมอน Rutzky

0

ทำไมคุณต้องมี PK?

ทำไมไม่เพียงไปกับ company_id เป็นดัชนีที่ไม่ใช่คลัสเตอร์?

คุณบอกว่าการสืบค้นส่วนใหญ่อยู่ในรายการทั้งหมดหรือโดย company_id
อัปเดต
แทบจะไม่ลบ
org_path นี่เป็นเพียงตารางเดียวที่มีอยู่

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

หากคุณกังวลเกี่ยวกับ DRI ตารางควรใช้ตาราง บริษัท เป็น FK สำหรับ company_id


เฮ้ เกี่ยวกับ " ทำไมไม่ไปกับ company_id เป็นดัชนีที่ไม่ใช่คลัสเตอร์? ": เพราะมันจะมี 2 ด้าน: 1) มันจะเป็นการเพิ่มพื้นที่อีก 1 อย่างในขณะที่ดัชนีแบบคลัสเตอร์เป็นตารางจึงไม่มีรายการเพิ่มเติมและ 2) มันจะยังคงต้องการการค้นหา RID เพื่อรับฟิลด์ NVARCHAR ยกเว้นว่าเป็นINCLUDEคอลัมน์ แต่ยิ่งแย่ลงเพราะเป็นเพียงการทำซ้ำตาราง จริงแล้ว PK ไม่จำเป็น ส่วนที่สำคัญคือดัชนีแบบกลุ่ม แต่เมื่อคุณมีตัวตนอาจจะไปกับ PK และโปรดดูลิงค์ใหม่ในคำตอบของฉันสำหรับการเดินผ่าน Uniquifier 😃
โซโลมอน Rutzky

@srutzky แต่มันก็หลีกเลี่ยง 4 ไบต์จำนวนเต็ม uniqueifier ดังนั้นผมจึงเห็นว่าเป็นล้าง
Paparazzo

ด้วยแถวที่น้อยกว่า 10k มันจะไม่เป็นไร คุณอาจต้องอยู่ในแถวหลายล้านแถวก่อนที่คุณจะสังเกตเห็นผลกระทบเพียง 4 ไบต์ ดังนั้นสำหรับข้อความค้นหา "รับทุกแถว" จึงไม่มีความแตกต่างในตัวเลือกเหล่านี้ แต่สำหรับเคียวรี "get for company_id = @param" การมีข้อมูลที่ร่างกายสั่งโดย company_id จะช่วยได้โดยเฉพาะอย่างยิ่งเมื่อไม่จำเป็นต้องทำการค้นหา RID สำหรับทุกแถว
โซโลมอน Rutzky

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