คำถามที่ดีมากเพราะเป็นแนวคิดที่สำคัญ นี่เป็นหัวข้อใหญ่และสิ่งที่ฉันจะแสดงให้คุณเห็นคือความเรียบง่ายเพื่อให้คุณสามารถเข้าใจแนวคิดพื้นฐาน
ประการแรกเมื่อคุณเห็นตารางดัชนีคิดว่ากลุ่ม ในเซิร์ฟเวอร์ 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 สัญกรณ์สำหรับการดำเนินการค้นหามีดังนี้:
- ทำการค้นหาแบบไบนารีบนดัชนีคลัสเตอร์โดยเปรียบเทียบค่าที่ค้นหากับค่าในระดับกลาง
- ส่งคืนค่าที่ตรงกัน (โปรดจำไว้ว่าเนื่องจากดัชนีคลัสเตอร์มีข้อมูลทั้งหมดในนั้นสามารถส่งคืนคอลัมน์ทั้งหมดจากดัชนีเนื่องจากเป็นข้อมูลแถว)
ดังนั้นจึงเป็นการดำเนินการสองอย่าง อย่างไรก็ตามหากเราดำเนินการค้นหาต่อไปนี้:
SELECT * FROM Customer WHERE CustomerName ='John'
SQL จะใช้ดัชนีที่ไม่ทำคลัสเตอร์บน CustomerName เพื่อทำการค้นหา อย่างไรก็ตามเนื่องจากนี่เป็นดัชนีที่ไม่ได้ทำคลัสเตอร์จึงไม่มีข้อมูลทั้งหมดในแถว
ดังนั้น SQL จะทำการค้นหาในระดับกลางเพื่อค้นหาระเบียนที่ตรงกันจากนั้นทำการค้นหาโดยใช้ค่าที่ส่งคืนเพื่อทำการค้นหาอีกครั้งในดัชนีคลัสเตอร์ (aka ตาราง) เพื่อดึงข้อมูลจริง เสียงนี้ทำให้ฉันสับสน แต่อ่านแล้วทุกอย่างจะชัดเจน
เนื่องจากดัชนีที่ไม่ใช่คลัสเตอร์ของเรามีเฉพาะชื่อลูกค้า (ค่าฟิลด์ดัชนีที่เก็บไว้ในโหนดกลาง) และตัวชี้ไปยังข้อมูลซึ่งเป็น CustomerID ดัชนีจึงไม่มีเร็กคอร์ดของชื่อลูกค้า CustomerSurname จะต้องดึงข้อมูลจากดัชนีหรือตารางคลัสเตอร์
เมื่อเรียกใช้แบบสอบถามนี้ฉันจะได้รับแผนการดำเนินการต่อไปนี้:
มีสองสิ่งสำคัญที่คุณจะสังเกตเห็นในภาพหน้าจอด้านบน
- SQL กำลังบอกว่าฉันมีดัชนีหายไป (ข้อความเป็นสีเขียว) SQL แนะนำให้ฉันสร้างดัชนีบน CustomerName ซึ่งรวมถึง CustomerID และ CustomerSurname
- คุณจะเห็นว่า 99% ของเวลาที่ใช้ในการค้นหาคีย์ในดัชนีคีย์หลัก / ดัชนีคลัสเตอร์
ทำไม SQL ถึงแนะนำดัชนีใน CustomerName อีกครั้ง? เนื่องจากดัชนีมีเพียง CustomerID และ CustomerName SQL ยังคงต้องค้นหา CustomerSurname จากดัชนีตาราง / คลัสเตอร์
หากเราสร้างดัชนีและเรารวมคอลัมน์ CustomerSurname ไว้ในดัชนี SQL จะสามารถตอบสนองการสืบค้นทั้งหมดโดยเพียงแค่อ่านดัชนีที่ไม่ใช่คลัสเตอร์ นี่คือเหตุผลที่ SQL แนะนำให้ฉันเปลี่ยนดัชนีที่ไม่ใช่คลัสเตอร์
ที่นี่คุณสามารถเห็นการดำเนินการพิเศษของ SQL ที่ต้องทำเพื่อรับคอลัมน์ CustomerSurname จากคีย์คลัสเตอร์
ดังนั้นจำนวนการดำเนินการมีดังนี้:
- ค้นหาไบนารีด้วยดัชนีที่ไม่ทำคลัสเตอร์โดยเปรียบเทียบค่าที่ค้นหากับค่าในระดับกลาง
- สำหรับโหนดที่ตรงกับอ่านโหนดระดับลีฟซึ่งจะมีตัวชี้สำหรับข้อมูลในดัชนีคลัสเตอร์ (โหนดระดับลีฟจะมีค่าคีย์หลักโดยวิธี)
- สำหรับแต่ละค่าที่ส่งคืนให้อ่านในดัชนีคลัสเตอร์ (ตาราง) เพื่อรับค่าแถวออกจากที่นี่เราจะอ่าน CustomerSurname
- ส่งคืนแถวที่ตรงกัน
นั่นคือการดำเนินการ 4 อย่างเพื่อให้ได้ค่าออกมา จำนวนการดำเนินการที่จำเป็นสองเท่าเมื่อเปรียบเทียบกับการอ่านดัชนีคลัสเตอร์ แสดงให้คุณเห็นว่าดัชนีคลัสเตอร์ของคุณเป็นดัชนีที่ทรงพลังที่สุดเนื่องจากมีข้อมูลทั้งหมด
ดังนั้นเพียงแค่ชี้แจงจุดสุดท้าย ทำไมฉันถึงบอกว่าตัวชี้ในดัชนีที่ไม่ใช่คลัสเตอร์เป็นค่าคีย์หลัก ดีที่จะแสดงให้เห็นว่าโหนดระดับใบของดัชนีที่ไม่คลัสเตอร์มีค่าคีย์หลักที่ฉันเปลี่ยนแบบสอบถามของฉันไปที่:
SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'
ในแบบสอบถามนี้ SQL สามารถอ่าน CustomerID จากดัชนีที่ไม่ใช่คลัสเตอร์ ไม่จำเป็นต้องทำการค้นหาบนดัชนีคลัสเตอร์ สิ่งนี้คุณสามารถเห็นได้จากแผนการดำเนินการซึ่งมีลักษณะเช่นนี้
สังเกตเห็นความแตกต่างระหว่างแบบสอบถามนี้และแบบสอบถามก่อนหน้า ไม่มีการค้นหา SQL สามารถค้นหาข้อมูลทั้งหมดในดัชนีที่ไม่ใช่คลัสเตอร์
หวังว่าคุณสามารถเริ่มเข้าใจว่าดัชนีคลัสเตอร์เป็นตารางและดัชนีที่ไม่ใช่คลัสเตอร์ไม่ประกอบด้วยข้อมูลทั้งหมด การจัดทำดัชนีจะเพิ่มความเร็วในการเลือกเนื่องจากข้อเท็จจริงที่ว่าการค้นหาแบบไบนารีสามารถทำได้ แต่ดัชนีแบบกลุ่มเท่านั้นที่มีข้อมูลทั้งหมด ดังนั้นการค้นหาดัชนีที่ไม่ทำคลัสเตอร์จะส่งผลให้ค่าการโหลดจากดัชนีคลัสเตอร์เกือบตลอดเวลา การดำเนินการพิเศษเหล่านี้ทำให้ดัชนีที่ไม่ทำคลัสเตอร์มีประสิทธิภาพน้อยกว่าดัชนีที่ทำคลัสเตอร์
หวังว่านี่จะช่วยล้างสิ่งต่างๆ หากมีอะไรที่ไม่สมเหตุสมผลโปรดโพสต์ความคิดเห็นและฉันจะพยายามชี้แจง มันค่อนข้างช้าและสมองของฉันรู้สึกแบนเล็กน้อย เวลาสำหรับกระทิงแดง