ความแตกต่างของประสิทธิภาพระหว่างดัชนีแบบคลัสเตอร์และแบบไม่ทำดัชนี


22

ผมอ่านและClusteredNon Clustered Indexes

Clustered Index- มันมีหน้าข้อมูล นั่นหมายถึงข้อมูลแถวที่สมบูรณ์จะแสดงในคอลัมน์ดัชนีแบบกลุ่ม

Non Clustered Index- มีเฉพาะข้อมูลตัวระบุแถวในรูปแบบของคอลัมน์ดัชนีแบบคลัสเตอร์ (ถ้าไม่มีข้อมูล) หรือตัวระบุไฟล์ + หมายเลขหน้า + จำนวนแถวทั้งหมดในหน้า ซึ่งหมายความว่าเคียวรีเครื่องมือต้องใช้ขั้นตอนเพิ่มเติมเพื่อค้นหาข้อมูลจริง

ข้อความค้นหา - ฉันจะตรวจสอบความแตกต่างด้านประสิทธิภาพด้วยความช่วยเหลือของตัวอย่างที่ใช้งานจริงได้อย่างไรเนื่องจากเรารู้ว่าตารางสามารถมีได้เพียงรายการเดียวClustered Indexและจัดเตรียมsortingที่Clustered Index ColumnและNon Clustered Indexไม่ได้ให้บริการsortingและสามารถรองรับ 999 Non Clustered IndexesในSQL Server 2008และ 249 นิ้วSQL Server 2005ได้


2
แตกต่างประสิทธิภาพเมื่อคุณทำในสิ่งที่ ?, สิ่งที่ชนิดของงานที่คุณต้องการจะทำอย่างไรกับตารางที่มี ?, ไม่ได้เป็นทางออกเดียวที่เหมาะสมกับทุกความต้องการ
Lamak

2
บางการสนทนาที่จับต้องได้ที่นี่บางที stackoverflow.com/questions/91688/... stackoverflow.com/questions/5070529/... stackoverflow.com/questions/1251636/...เราสามารถเขียนวิทยานิพนธ์เกี่ยวกับความแตกต่างระหว่างดัชนีคลัสเตอร์และไม่ใช่คลัสเตอร์ แต่ผมไม่คิดว่าเรา จะพูดอะไรก็ตามที่ยังไม่มีให้คุณอ่าน
Aaron Bertrand

4
คุณเขียนว่า: "ซึ่งหมายความว่าเคียวรีเอ็นจินต้องใช้ขั้นตอนเพิ่มเติมเพื่อค้นหาข้อมูลจริง" ที่จริงแล้วถ้าสิ่งที่คุณต้องการคือคอลัมน์ที่ครอบคลุมในดัชนีคุณไม่จำเป็นต้องทำตามขั้นตอนเพิ่มเติมหลังจากที่คุณพบแถวเป้าหมายของคุณในดัชนีที่ไม่เป็นคลัสเตอร์ เฉพาะเมื่อคุณต้องการคอลัมน์ไม่ครอบคลุมโดยดัชนี nonclustered ไม่ SQL Server จำเป็นที่จะต้องดำเนินการค้นหาบุ๊คมาร์ค
Nick Chammas

คำตอบ:


43

คำถามที่ดีมากเพราะเป็นแนวคิดที่สำคัญ นี่เป็นหัวข้อใหญ่และสิ่งที่ฉันจะแสดงให้คุณเห็นคือความเรียบง่ายเพื่อให้คุณสามารถเข้าใจแนวคิดพื้นฐาน

ประการแรกเมื่อคุณเห็นตารางดัชนีคิดว่ากลุ่ม ในเซิร์ฟเวอร์ SQL ถ้าตารางไม่มีดัชนีคลัสเตอร์มันเป็นฮีป การสร้างดัชนีแบบคลัสเตอร์บนตารางจะแปลงตารางเป็นโครงสร้างชนิด b-tree ดัชนีคลัสเตอร์ของคุณคือตารางของคุณซึ่งไม่ได้แยกออกจากตาราง

เคยสงสัยไหมว่าทำไมคุณสามารถมีดัชนีกลุ่มเดียวได้? ถ้าเรามีดัชนีกลุ่มสองกลุ่มเราจะต้องใช้สำเนาสองชุดของตาราง มันมีข้อมูลหลังจากทั้งหมด

ฉันจะพยายามอธิบายโดยใช้ตัวอย่างง่ายๆ

หมายเหตุ:ฉันสร้างตารางในตัวอย่างนี้และเติมด้วยรายการสุ่มมากกว่า 3 ล้านรายการ จากนั้นเรียกใช้แบบสอบถามจริงและวางแผนการดำเนินการที่นี่

สิ่งที่คุณต้องการจริงๆที่จะเข้าใจเป็นสัญกรณ์ Oหรือประสิทธิภาพการดำเนินงาน สมมติว่าคุณมีตารางต่อไปนี้

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

ดังนั้นที่นี่เรามีตารางพื้นฐานที่มีคีย์คลัสเตอร์ใน CustomerID (คีย์หลักคือคลัสเตอร์โดยค่าเริ่มต้น) ดังนั้นตารางจะถูกจัดเรียง / สั่งซื้อโดยยึดตามรหัสลูกค้าหลัก ระดับกลางจะมีค่า CustomerID หน้าข้อมูลจะมีทั้งแถวจึงเป็นแถวของตาราง

นอกจากนี้เรายังจะสร้างดัชนีที่ไม่ทำคลัสเตอร์ในฟิลด์ CustomerName รหัสต่อไปนี้จะทำ

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

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

ถูกต้องดังนั้นหากเราดำเนินการค้นหาต่อไปนี้:

SELECT * FROM Customer WHERE CustomerID = 1 

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

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นจำนวนของการดำเนินการหรือ O สัญกรณ์สำหรับการดำเนินการค้นหามีดังนี้:

  1. ทำการค้นหาแบบไบนารีบนดัชนีคลัสเตอร์โดยเปรียบเทียบค่าที่ค้นหากับค่าในระดับกลาง
  2. ส่งคืนค่าที่ตรงกัน (โปรดจำไว้ว่าเนื่องจากดัชนีคลัสเตอร์มีข้อมูลทั้งหมดในนั้นสามารถส่งคืนคอลัมน์ทั้งหมดจากดัชนีเนื่องจากเป็นข้อมูลแถว)

ดังนั้นจึงเป็นการดำเนินการสองอย่าง อย่างไรก็ตามหากเราดำเนินการค้นหาต่อไปนี้:

SELECT * FROM Customer WHERE CustomerName ='John'

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

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

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

เมื่อเรียกใช้แบบสอบถามนี้ฉันจะได้รับแผนการดำเนินการต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

มีสองสิ่งสำคัญที่คุณจะสังเกตเห็นในภาพหน้าจอด้านบน

  1. SQL กำลังบอกว่าฉันมีดัชนีหายไป (ข้อความเป็นสีเขียว) SQL แนะนำให้ฉันสร้างดัชนีบน CustomerName ซึ่งรวมถึง CustomerID และ CustomerSurname
  2. คุณจะเห็นว่า 99% ของเวลาที่ใช้ในการค้นหาคีย์ในดัชนีคีย์หลัก / ดัชนีคลัสเตอร์

ทำไม SQL ถึงแนะนำดัชนีใน CustomerName อีกครั้ง? เนื่องจากดัชนีมีเพียง CustomerID และ CustomerName SQL ยังคงต้องค้นหา CustomerSurname จากดัชนีตาราง / คลัสเตอร์

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

ที่นี่คุณสามารถเห็นการดำเนินการพิเศษของ SQL ที่ต้องทำเพื่อรับคอลัมน์ CustomerSurname จากคีย์คลัสเตอร์

ดังนั้นจำนวนการดำเนินการมีดังนี้:

  1. ค้นหาไบนารีด้วยดัชนีที่ไม่ทำคลัสเตอร์โดยเปรียบเทียบค่าที่ค้นหากับค่าในระดับกลาง
  2. สำหรับโหนดที่ตรงกับอ่านโหนดระดับลีฟซึ่งจะมีตัวชี้สำหรับข้อมูลในดัชนีคลัสเตอร์ (โหนดระดับลีฟจะมีค่าคีย์หลักโดยวิธี)
  3. สำหรับแต่ละค่าที่ส่งคืนให้อ่านในดัชนีคลัสเตอร์ (ตาราง) เพื่อรับค่าแถวออกจากที่นี่เราจะอ่าน CustomerSurname
  4. ส่งคืนแถวที่ตรงกัน

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

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

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

ในแบบสอบถามนี้ SQL สามารถอ่าน CustomerID จากดัชนีที่ไม่ใช่คลัสเตอร์ ไม่จำเป็นต้องทำการค้นหาบนดัชนีคลัสเตอร์ สิ่งนี้คุณสามารถเห็นได้จากแผนการดำเนินการซึ่งมีลักษณะเช่นนี้

ป้อนคำอธิบายรูปภาพที่นี่

สังเกตเห็นความแตกต่างระหว่างแบบสอบถามนี้และแบบสอบถามก่อนหน้า ไม่มีการค้นหา SQL สามารถค้นหาข้อมูลทั้งหมดในดัชนีที่ไม่ใช่คลัสเตอร์

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

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


ผมมีคำถาม. WH คือการค้นหาดัชนีค้นหาในดัชนีที่ไม่ใช่คลัสเตอร์ใน CustomerName สำหรับแบบสอบถามนี้ SELECT * จากลูกค้า WHERE CustomerName = 'John' เนื่องจากเป็นดัชนีที่ไม่ใช่แบบคลัสเตอร์ชื่อผู้ใช้จะไม่ถูกจัดเรียง ดังนั้นไม่ควรทำการสแกนดัชนี
ckv

BTW คำตอบที่ดีเข้าใจทั้งหมดยกเว้นคำถามข้างต้น
ckv

1
ดัชนีจะเรียงตามลำดับของข้อมูล ตัวอย่างเช่นมันจะถูกจัดเรียงในชื่อลูกค้าเนื่องจากเป็นค่าดัชนี ดังนั้นมันจึงถูกจัดเรียง จำไว้ว่ามันยังคงต้องสแกนระดับใบไม้หรือหน้า
Namphibian

9

"ซึ่งหมายความว่าเคียวรีเครื่องมือต้องใช้ขั้นตอนเพิ่มเติมเพื่อค้นหาข้อมูลจริง"

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

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

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

และฉันไม่ต้องกังวลเกี่ยวกับขีด จำกัด ของดัชนีต่าง ๆ ที่อนุญาต - นั่นแทบจะไม่เกิดขึ้นกับตัวอย่างจริง ๆ มากมาย


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