ตัวอย่างในคำถามนั้นไม่ได้ให้ผลลัพธ์ที่เหมือนกันเลย ( OFFSET
ตัวอย่างมีข้อผิดพลาดแบบแยกจากกัน) แบบฟอร์มที่อัปเดตด้านล่างแก้ไขปัญหานั้นลบการเรียงลำดับพิเศษสำหรับROW_NUMBER
เคสและใช้ตัวแปรเพื่อทำให้การแก้ปัญหาเป็นเรื่องทั่วไปมากขึ้น:
DECLARE
@PageSize bigint = 10,
@PageNumber integer = 3;
WITH Numbered AS
(
SELECT TOP ((@PageNumber + 1) * @PageSize)
o.*,
rn = ROW_NUMBER() OVER (
ORDER BY o.[object_id])
FROM #objects AS o
ORDER BY
o.[object_id]
)
SELECT
x.name,
x.[object_id],
x.principal_id,
x.[schema_id],
x.parent_object_id,
x.[type],
x.type_desc,
x.create_date,
x.modify_date,
x.is_ms_shipped,
x.is_published,
x.is_schema_published
FROM Numbered AS x
WHERE
x.rn >= @PageNumber * @PageSize
AND x.rn < ((@PageNumber + 1) * @PageSize)
ORDER BY
x.[object_id];
SELECT
o.name,
o.[object_id],
o.principal_id,
o.[schema_id],
o.parent_object_id,
o.[type],
o.type_desc,
o.create_date,
o.modify_date,
o.is_ms_shipped,
o.is_published,
o.is_schema_published
FROM #objects AS o
ORDER BY
o.[object_id]
OFFSET @PageNumber * @PageSize - 1 ROWS
FETCH NEXT @PageSize ROWS ONLY;
ROW_NUMBER
แผนมีค่าใช้จ่ายโดยประมาณของ0.0197935 :
OFFSET
แผนมีค่าใช้จ่ายโดยประมาณของ0.0196955 :
นั่นคือการประหยัดหน่วยต้นทุนโดยประมาณ0.000098 (แม้ว่าOFFSET
แผนจะต้องการตัวดำเนินการเพิ่มเติมหากคุณต้องการส่งคืนหมายเลขแถวสำหรับแต่ละแถว) OFFSET
แผนจะยังคงมีราคาถูกกว่าเล็กน้อยโดยทั่วไปการพูด แต่จำไว้ว่าค่าใช้จ่ายที่คาดว่าจะได้ตรงนั้น - การทดสอบที่แท้จริงจะต้องยังคง ค่าใช้จ่ายจำนวนมากในทั้งสองแผนคือค่าใช้จ่ายของชุดอินพุตแบบเต็มดังนั้นดัชนีที่เป็นประโยชน์จะเป็นประโยชน์ต่อทั้งสองโซลูชัน
ในกรณีที่ใช้ค่าตัวอักษรคงที่ (เช่นOFFSET 30
ในตัวอย่างดั้งเดิม) เครื่องมือเพิ่มประสิทธิภาพสามารถใช้การเรียง TopN แทนการเรียงแบบเต็มตามด้วยอันดับสูงสุด เมื่อแถวที่ต้องการจากการเรียง TopN เป็นตัวอักษรคงที่และ <= 100 (ผลรวมของOFFSET
และFETCH
) เอ็นจิ้นการดำเนินการสามารถใช้อัลกอริทึมการเรียงลำดับที่แตกต่างกันซึ่งสามารถทำงานได้เร็วกว่าการเรียง TopN ทั่วไป ทั้งสามกรณีมีลักษณะประสิทธิภาพโดยรวมแตกต่างกัน
สาเหตุที่เครื่องมือเพิ่มประสิทธิภาพไม่แปลงROW_NUMBER
รูปแบบไวยากรณ์ให้ใช้โดยอัตโนมัติOFFSET
มีสาเหตุหลายประการ:
- แทบจะเป็นไปไม่ได้เลยที่จะเขียนการแปลงรูปแบบที่เหมาะกับการใช้งานที่มีอยู่
- การมีคิวรี่เพจจิ้งโดยอัตโนมัติเปลี่ยนไปและคนอื่นอาจไม่สับสน
OFFSET
แผนไม่ได้รับประกันว่าจะดีขึ้นในทุกกรณี
ตัวอย่างหนึ่งสำหรับจุดที่สามด้านบนเกิดขึ้นที่ชุดการเพจค่อนข้างกว้าง มันอาจจะมีประสิทธิภาพมากขึ้นในการแสวงหากุญแจที่จำเป็นในการใช้ดัชนี nonclustered ด้วยตนเองและค้นหากับดัชนีคลัสเตอร์เมื่อเทียบกับการสแกนดัชนีด้วยหรือOFFSET
ROW_NUMBER
มีปัญหาเพิ่มเติมที่ต้องพิจารณาหากแอปพลิเคชันการเพจต้องการทราบจำนวนแถวหรือหน้าทั้งหมด มีอีกสนทนาที่ดีของญาติของ 'คีย์แสวงหา' และวิธีการ 'ชดเชย' ที่นี่
โดยรวมแล้วน่าจะดีกว่าที่ผู้คนจะทำการตัดสินใจอย่างมีข้อมูลเพื่อเปลี่ยนคิวรี่เพจจิ้งเพื่อใช้OFFSET
หากเหมาะสมหลังจากการทดสอบอย่างละเอียด