เมื่อใดควรประกาศคีย์หลักที่ไม่ใช่แบบคลัสเตอร์


169

ในขณะที่สร้างฐานข้อมูลทดสอบสำหรับคำถามอื่นที่ฉันถามไปก่อนหน้านี้ฉันจำเกี่ยวกับคีย์หลักที่สามารถประกาศได้ NONCLUSTERED

คุณจะใช้NONCLUSTEREDคีย์หลักตรงข้ามกับCLUSTEREDคีย์หลักเมื่อใด

ขอบคุณล่วงหน้า

คำตอบ:


187

คำถามไม่ใช่ 'เมื่อ PK ควรเป็น NC' แต่คุณควรถามว่า 'อะไรคือคีย์ที่เหมาะสมสำหรับดัชนีคลัสเตอร์'

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

ปริศนาอีกชิ้นคือดัชนีสามารถใช้งานได้อย่างไร? มีสามรูปแบบทั่วไป:

  • โพรบเมื่อค้นหาค่าคีย์เดียวในดัชนี
  • สแกนช่วงเมื่อช่วงของค่าคีย์ถูกดึง
  • เรียงตามความต้องการเมื่อดัชนีสามารถตอบสนองคำสั่งซื้อโดยไม่ต้องมีการเรียงลำดับหยุดและไป

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

แต่อีกปัจจัยหนึ่งคือการที่สำคัญดัชนีคลัสเตอร์เป็นกุญแจสำคัญในการค้นหาที่ใช้โดยทั้งหมดดัชนีไม่มีคลัสเตอร์และดังนั้นจึงคีย์ดัชนีคลัสเตอร์กว้างสร้างผลกระเพื่อมและกว้างทั้งหมดดัชนีไม่มีคลัสเตอร์และดัชนีกว้างหมายถึงหน้ามากขึ้น I / O หน่วยความจำมากขึ้นความดีน้อยลง

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

และดัชนีกลุ่มที่ดีจะเพิ่มขึ้นตามลำดับโดยไม่สุ่ม (แต่ละค่าคีย์ที่แทรกใหม่มีขนาดใหญ่กว่าค่าก่อนหน้า) เพื่อหลีกเลี่ยงการแยกหน้าและการแตกแฟรกเมนต์ (โดยไม่ยุ่งกับFILLFACTORs)

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

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

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


1
"จัดเรียงตามความต้องการเมื่อดัชนีสามารถตอบสนองคำสั่งซื้อโดยไม่มีการจัดเรียงหยุดและไป" หมายความว่าที่นี่?
Mike Sherrill 'Cat Recall'

2
@RemusRusanu +1 คำตอบที่มีประโยชน์มาก (state, id)หนึ่งคำถามเกี่ยวกับตัวอย่าง ในตัวอย่างนี้ความต้องการ "ดัชนีคลัสเตอร์ที่ดีจะเพิ่มขึ้นตามลำดับไม่สุ่ม" จะไม่เป็นเช่นนั้นใช่ไหม ดังนั้นเราสามารถพิจารณาว่าเป็นดัชนีกลุ่มที่ดีหรือไม่
Lijo

26

เหตุผลพื้นฐานในการใช้ดัชนีแบบคลัสเตอร์มีการระบุไว้ในWikipedia :

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

บอกว่าฉันมีตารางคนและคนเหล่านี้มีคอลัมน์ประเทศและคีย์หลักที่ไม่ซ้ำกัน เป็นตารางข้อมูลประชากรดังนั้นสิ่งเหล่านี้เป็นสิ่งเดียวที่ฉันสนใจ ประเทศใดและมีผู้คนที่เป็นเอกลักษณ์จำนวนเท่าใดที่เชื่อมโยงกับประเทศนั้น

ฉันมักจะเลือกที่ใดก็ได้หรือเรียงตามคอลัมน์ประเทศ; ดัชนีคลัสเตอร์ในคีย์หลักไม่ได้ทำอะไรให้ฉันดีฉันไม่ได้เข้าถึงข้อมูลนี้โดย PK ฉันกำลังเข้าถึงโดยคอลัมน์อื่นนี้ เนื่องจากฉันสามารถมีดัชนีคลัสเตอร์เดียวได้บนโต๊ะการประกาศ PK ของฉันเนื่องจาก Clustered จะป้องกันไม่ให้ฉันใช้ดัชนีแบบกลุ่มในประเทศ

นอกจากนี้ต่อไปนี้เป็นบทความที่ดีเกี่ยวกับดัชนีที่ไม่ได้ทำคลัสเตอร์แบบไม่รวมกลุ่มกลายเป็นดัชนีแบบกลุ่มทำให้เกิดปัญหาประสิทธิภาพการแทรกใน SQL Server 6.5 (ซึ่งอย่างน้อยหวังว่าจะไม่เกี่ยวข้องกับพวกเราส่วนใหญ่ที่นี่)

หากคุณใส่ดัชนีแบบกลุ่มในคอลัมน์ตัวตนเม็ดมีดทั้งหมดของคุณจะเกิดขึ้นในหน้าสุดท้ายของตาราง - และหน้านั้นจะถูกล็อคตามระยะเวลาของแต่ละ IDENTITY ไม่มีเรื่องใหญ่ ... เว้นแต่คุณจะมีคน 5,000 คนที่ต้องการหน้าสุดท้าย จากนั้นคุณมีข้อโต้แย้งมากมายสำหรับหน้านั้น

โปรดทราบว่านี่ไม่ใช่กรณีในรุ่นที่ใหม่กว่า


3
FIY, คุณพูดถึง SQL Server 6.5: dba.stackexchange.com/questions/1584/…
gbn

15

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


1
ในขณะที่ฉันพยายามหลีกเลี่ยง UUID สำหรับคีย์ที่ทำคลัสเตอร์ฉันเชื่อว่าเหตุผลข้างต้นอาจไม่สมบูรณ์ เซิร์ฟเวอร์ SQL ไม่จำเป็นต้องสลับแถวเพื่อแทรก a ในตำแหน่งที่ถูกต้อง (ถ้าคุณหมายถึง "ระหว่างค่าที่ต่ำกว่าและสูงกว่า") พิจารณาการแทรกลงในกลางแถวตารางล้านล้าน ความต้องการทางอ้อมที่เพิ่มขึ้นซึ่งอาจเป็นสิ่งที่คุณต้องการ UNIQUEIDENTIFIERชนิดของการเรียงลำดับมีอยู่ด้วยและมีความน่าจะเป็นเหมือนกันในการสร้างคีย์ที่ไม่ซ้ำกันแม้ว่ามันจะยังคงทนทุกข์ทรมานจากขนาด 128
Charles Burns

7

ตัวอย่างทั่วไป:

  • Customerตารางที่มีCustomerIDฐานะCLUSTERED PRIMARY KEY
  • สั่งซื้อตารางด้วยOrderID (PK), CustomerID, OrderDateและคอลัมน์อื่น ๆ
  • OrderPositions กับ OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • คุณต้องทำดัชนีตารางการสั่งซื้อ

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

OrderIDในกรณีนี้ก็จะทำให้รู้สึกไม่มากที่จะจัดกลุ่มตารางโดย ใช่คุณจะมีข้อความค้นหาSELECT ... WHERE OrderId = ?เพื่อแสดงรายละเอียดการสั่งซื้อ แต่โดยปกติจะเป็นการค้นหาดัชนีสั้น ๆ และราคาถูก (3 ครั้ง)

ในทางตรงกันข้ามถ้าคุณจะคลัสเตอร์ของคุณOrderตารางโดยมันจะไม่ต้องทำการค้นหาที่สำคัญหลายครั้งที่คุณสอบถามตารางสำหรับCustomerIDCustomerId = ?

CLUSTERED INDEXควรจะเสมอUNIQUEมิฉะนั้น SQL Server จะเพิ่มที่มองไม่เห็น (= ใช้ไม่ได้) คอลัมน์ INT UNIQUIFIERเพื่อให้แน่ใจว่า uniquiness - และมันจะทำให้รู้สึกมากขึ้นเพื่อเพิ่มจริงข้อมูล (งาน) แล้วบางสุ่ม (ขึ้นอยู่กับคำสั่งแทรก) สิ่ง

เนื่องจากลูกค้าจะ (หวังว่า) จะสั่งซื้อมากกว่าหนึ่งคำสั่งซื้อเราจะต้องเพิ่มอย่างใดอย่างหนึ่งOrderIDหรือ (ถ้าคุณมักจะเรียงลำดับนี้) ที่OrderDate(ถ้ามันเป็นวันที่และเวลา - มิฉะนั้นลูกค้าจะถูก จำกัด เพียงหนึ่งคำสั่งต่อวัน) CLUSTERED INDEXและจบลงด้วย:

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

กฎเดียวกันนี้ใช้กับOrderPositionsตาราง มักจะมีคำสั่งส่วนใหญ่จะแสดงรายการทุกตำแหน่งสำหรับการสั่งซื้อที่เฉพาะเจาะจงเพื่อคุณควรสร้าง PK ที่มีOrderPositionIDฐานะNONCLUSTEREDและบนUNIQUE CLUSTERED INDEXOrderId, OrderPositionID

BTW: มันถูกต้องว่าCustomerตารางนั้นมีการรวมกลุ่มโดย PK (the CustomerID, เพราะมันเป็น "Top-Level-Table" และจะ - ในแอปพลิเคชันทั่วไป - ส่วนใหญ่จะถูกสอบถามโดย CustomerID

ตารางการค้นหาบริสุทธิ์เป็นเช่นGendersหรือInvoiceTypesหรือPaymentTypeเป็นอีกตัวอย่างหนึ่งของตารางที่ควรจะคลัสเตอร์โดย PK มัน (เพราะคุณมักจะเข้าร่วมพวกเขาในGenderId, InvoiceTypeIdหรือPaymentTypeId)


2

เมื่อดัชนีกลุ่มถือว่ามีประโยชน์ต่อระบบโดยรวมมากกว่า PK แบบคลัสเตอร์โดยใช้การวัดประสิทธิภาพ สามารถมีดัชนีคลัสเตอร์ได้หนึ่งรายการเท่านั้นในตาราง

ตัวอย่างการวัดประสิทธิภาพคือเวลาแบบสอบถามเดียว (ความเร็ว), การรวมเวลาแบบสอบถามทั้งหมดกับตาราง (ประสิทธิภาพ) และต้องเพิ่มคอลัมน์หลายคอลัมน์ลงใน a ไปยังดัชนีที่ไม่ใช่คลัสเตอร์ขนาดใหญ่มากเพื่อให้ได้ประสิทธิภาพคล้ายกับคลัสเตอร์ (ขนาด )

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

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