การแบ่งหน้าใน SQL Server


17

ฉันมีฐานข้อมูลขนาดใหญ่มากประมาณ 100 GB ฉันกำลังดำเนินการค้นหา:

select * from <table_name>;

และฉันต้องการแสดงแถวที่ 100 ถึง 200 เท่านั้น

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

ฉันพบว่าสิ่งนี้เกี่ยวข้องกับแนวคิดเรื่องการแบ่งหน้า แต่ฉันไม่สามารถหาได้ว่ามันเกิดขึ้นภายในระดับฐานข้อมูลได้อย่างไร

คำตอบ:


37

ในแบบสอบถามที่คุณโพสต์:

select * from <table_name>;

ไม่มีสิ่งเช่นแถวที่ 100 ถึง 200 เพราะคุณไม่ได้ระบุ ORDER BY การสั่งซื้อจะไม่รับประกันถ้าคุณไม่ได้รวม ORDER BY ด้วยเหตุผลที่น่าสนใจมากมาย แต่นั่นไม่ใช่จุดที่นี่

ดังนั้นเพื่อแสดงจุดของคุณลองใช้ตาราง - ฉันจะใช้ตารางผู้ใช้จากการถ่ายโอนข้อมูลกองข้อมูลล้นและเรียกใช้แบบสอบถามนี้:

SELECT * FROM dbo.Users ORDER BY DisplayName;

ตามค่าเริ่มต้นไม่มีดัชนีในเขตข้อมูล DisplayName ดังนั้น SQL Server ต้องสแกนตารางทั้งหมดแล้วเรียงลำดับตาม DisplayName นี่คือแผนการดำเนินการ :

การสแกนดัชนีแบบกลุ่มพร้อมการจัดเรียง

มันไม่สวยเลย - มันใช้งานได้ดีมาก, ด้วยราคาทรีย่อยประมาณ 30k (คุณสามารถดูได้โดยการเลื่อนเมาส์ไปเหนือตัวดำเนินการที่เลือกที่ PasteThePlan) จะเกิดอะไรขึ้นหากเราต้องการแถวที่ 100-200 เท่านั้น เราสามารถใช้ไวยากรณ์นี้ใน SQL Server 2012+:

SELECT * FROM dbo.Users ORDER BY DisplayName OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY;

แผนการดำเนินการที่น่าเกลียดเกินไป:

การสแกนดัชนีแบบกลุ่มพร้อมการจัดเรียงและส่วนบน

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

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

CREATE INDEX IX_DisplayName ON dbo.Users(DisplayName);

ด้วยดัชนีนั้นขณะนี้แผนการดำเนินการค้นหาของเราจะค้นหาดัชนี:

ค้นหาดัชนีและค้นหาคีย์

การค้นหาเสร็จสิ้นทันทีและมีค่าใช้จ่ายทรีย่อยโดยประมาณเพียง 0.66 (เมื่อเทียบกับ 30k)

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


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

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

@AnilVedala เกี่ยวกับคำถามแรกของคุณ - ใช่ข้อมูลจะต้องมีการจัดเรียง ฐานข้อมูลสามารถทำได้อย่างไรด้วยรายการที่ไม่เรียงลำดับ
Brent Ozar

1
@AnilVedala เกี่ยวกับคำถามที่สองของคุณ - นั่นคือแผนปฏิบัติการครั้งสุดท้ายที่ฉันให้คุณเข้ามา (ถ้าคุณถามเกี่ยวกับวิธีการอ่านแผนปฏิบัติการให้หยิบหนังสือแผนการดำเนินการโดย Grant Fritchey)
Brent Ozar

15

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

SELECT * 
FROM dbo.Users 
ORDER BY DisplayName 
OFFSET 100000 ROWS 
FETCH NEXT 100 ROWS ONLY;

แผนการดำเนินการแสดงให้เห็นว่าการค้นหาถูกดำเนินการ 100,100 ครั้งแม้ว่าทั้งหมดยกเว้น 100 แถวจะถูกกรองออกโดยผู้ดำเนินการ TOP

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

สิ่งนี้สามารถบรรเทาได้โดยใช้รูปแบบด้านล่าง

WITH T
     AS (SELECT Id,
                DisplayName
         FROM   dbo.Users
         ORDER  BY DisplayName
        OFFSET 100000 ROWS 
        FETCH NEXT 100 ROWS ONLY
        )
SELECT U.*
FROM   dbo.Users U
       JOIN T
         ON U.Id = T.Id
ORDER  BY T.DisplayName 

สิ่งนี้จะกรองออกทั้งหมดยกเว้นแถวสุดท้าย 100 แถวก่อนทำการค้นหาซึ่งอาจมีผลกระทบอย่างมากต่อความเร็วสำหรับค่าออฟเซ็ตขนาดใหญ่

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


3

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

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

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