ลำดับฟิลด์ในลำดับดัชนีคอมโพสิตที่มีการเลือกสูงและฟิลด์การเลือกต่ำ


11

ฉันมีตาราง SQL Server ที่มีมากกว่า 3 พันล้านแถว หนึ่งในคำถามของฉันใช้เวลานานมากดังนั้นฉันจึงพิจารณาที่จะเพิ่มประสิทธิภาพ แบบสอบถามมีลักษณะดังนี้:

SELECT [Enroll_Date]
      ,Count(*) AS [Record #]
      ,Count(Distinct UserID) AS [User #]
  FROM UserTable
  GROUP BY [Enroll_Date]

[Enroll_Date] เป็นคอลัมน์การเลือกต่ำที่มีค่าน้อยกว่า 50 ค่าในขณะที่คอลัมน์ UserID เป็นคอลัมน์เลือกสูงที่มีค่าแตกต่างกันมากกว่า 200 ล้านรายการ จากการวิจัยของฉันฉันเชื่อว่าฉันควรสร้างดัชนีคอมโพสิตแบบไม่รวมกลุ่มในสองคอลัมน์นี้และในทางทฤษฎีแล้วคอลัมน์การเลือกสูงควรเป็นคอลัมน์แรก แต่ฉันไม่แน่ใจว่าในกรณีของฉันจะทำงานได้เพราะฉันใช้คอลัมน์หัวกะทิต่ำในกลุ่มโดยข้อ

ตารางนี้ไม่มีดัชนีคลัสเตอร์


คุณสามารถโพสต์แผนการดำเนินการจริง xml (ใช้ pastebin และเชื่อมโยงได้ที่นี่) คุณใช้ SQL Server เวอร์ชั่นใด
Kin Shah

3
ดัชนีที่มีคอลัมน์ที่มีการคัดเลือกสูงอันดับแรกจะไม่มีประโยชน์สำหรับการสืบค้นเฉพาะ
ypercubeᵀᴹ

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

คำตอบ:


12

ในฐานะที่เป็นทางเลือกในการแก้ปัญหา @ AaronBertrand ฯ (ถ้าคุณไม่สามารถหรือไม่ต้องการที่จะสร้างมุมมองที่จัดทำดัชนี) (Enroll_Date, UserID)ฉันอยากจะแนะนำให้คุณสร้างดัชนีใน หากคำถามประเภทนี้พบได้บ่อยบนโต๊ะของคุณนี่อาจเป็นดัชนีที่จัดเป็นกลุ่มของคุณ

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

ดัชนีใน(Enroll_Date, UserID)จะให้แผนแบบสอบถามที่ปรับให้เหมาะสมและไม่มีการบล็อกด้วยการรวมสตรีม

สตรีมแผนแบบสอบถามรวม

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


ตลกห่างกัน 4 วินาทีและคำตอบเดียวกัน
usr

11

คำตอบ Aarons เป็นทางออกที่ดี ฉันจะตอบคำถามสมมติว่าคุณไม่ต้องการใช้วิธีการนั้น

แบบสอบถามที่คุณโพสต์จะมักจะดำเนินการโดยการจัดกลุ่มเป็นครั้งแรกในแล้วอีกครั้งใน(Enroll_Date, UserID) (Enroll_Date)การเพิ่มประสิทธิภาพนี้เป็นของใหม่กับ SQL Server 2012 COUNT DISTINCTมันจะมีผลในกรณีที่เป็นหนึ่งเดียว

ดัชนีในคอลัมน์ทั้งสองในลำดับที่เฉพาะเจาะจง(Enroll_Date, UserID)จะพอเพียงเพื่อให้ได้แผนที่มีประสิทธิภาพซึ่งจะทำให้การสแกนดัชนีเป็นช่องทางรวมสองรายการที่ต่อเนื่องกัน ลำดับตรงกันข้ามจะไม่เปิดใช้งานแผนนั้น

(Enroll_Date, UserID)ดังนั้นการใช้คำสั่ง คุณไม่มีทางเลือกที่นี่


กัน 5 วินาทีและทางออกเดียวกัน เล่นได้ดีครับ :)
Daniel Hutmacher

@DanielHutmacher OMG เราจะจัดการเกือบจะตรงกับโพสต์ของเราเป็นครั้งที่ 3! +1 ถึงคุณ! ฉันจะไม่ตอบคำตอบที่เหมือนกันได้อย่างไร
usr

ความผิดพลาดในเมทริกซ์ :)
Daniel Hutmacher

ขอบคุณมาก. ฉันกำลังสร้างดัชนีและจะโพสต์การปรับปรุงหลังจากเสร็จสิ้น รุ่นของเซิร์ฟเวอร์คือ Microsoft SQL Server 2008 R2 บน AWS แต่ฉันเดาว่ามันยังคงเป็นตัวเลือกเดียวที่ไม่ว่า
คิด

@ นักคิดในกรณีที่คุณไม่ยอมรับวิธีการของ Aarons คุณมีทางเลือกที่ยากลำบาก :)
usr

11

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

CREATE VIEW dbo.MyIndexedView
WITH SCHEMABINDING
AS 
  SELECT Enroll_Date, UserID, RawCount = COUNT_BIG(*)
  FROM dbo.UserTable
  GROUP BY Enroll_Date, UserID;
GO

CREATE UNIQUE CLUSTERED INDEX CIX_miv ON dbo.MyIndexedView(Enroll_Date, UserID);

ซึ่งจะใช้เวลาสักครู่ในการสร้างและแน่นอนว่าจะต้องมีการบำรุงรักษาตลอดการดำเนินการ DML ทั้งหมดเช่นเดียวกับดัชนีในตารางฐาน

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

SELECT Enroll_Date, 
  [Record #] = SUM(RawCount),
  [User #] = COUNT(*)
FROM dbo.MyIndexedView WITH (NOEXPAND)
GROUP BY Enroll_Date; 

เพิ่ม NOEXPAND คำใบ้หลังจากจดจำนี้และนี้

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

และถ้าคุณใช้คำสั่ง WHERE ทั่วไปร่วมกันที่เหมือนกันกับ Enroll_Date สำหรับช่วงที่กำหนดไว้ชัดเจน (เช่นไตรมาสปัจจุบันหรือปีปัจจุบัน) คุณสามารถเพิ่มดัชนีที่กรองที่ตรงกันซึ่งลด I / O ให้มากขึ้น (แต่มีเสมอ การออก)

คุณอาจพิจารณาวางดัชนีคลัสเตอร์บนตารางฐาน นี่ไม่ใช่กรณีการใช้งานที่หายากซึ่งได้รับประโยชน์จากฮีป


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

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

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