เพจจิ้งทำงานกับ ROW_NUMBER ใน SQL Server ได้อย่างไร


13

ฉันมีEmployeeตารางที่มีหนึ่งล้านบันทึก ฉันได้ติดตาม SQL สำหรับข้อมูลการเพจในเว็บแอปพลิเคชัน มันทำงานได้ดี อย่างไรก็ตามสิ่งที่ฉันเห็นว่าเป็นปัญหาคือ - ตารางที่ได้รับtblEmployeeจะเลือกระเบียนทั้งหมดในEmployeeตาราง (เพื่อสร้าง MyRowNumberค่า)

ฉันคิดว่านี่เป็นสาเหตุของการเลือกระเบียนทั้งหมดในEmployeeตาราง

มันใช้งานได้จริงเหรอ? หรือ SQL Server นั้นได้รับการปรับแต่งให้เลือกเฉพาะ 5 ระเบียนจากEmployeeตารางต้นฉบับด้วยหรือไม่

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 

3
ดูsqlservercentral.com/articles/T-SQL/66030และที่สำคัญการอภิปรายที่ตามมา
Aaron Bertrand

คำตอบ:


17

ทางเลือกในการทดสอบอาจเป็น:

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

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

http://www.sqlservercentral.com/articles/T-SQL/66030/

และการสนทนาติดตามผล:

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

ใน SQL Server 2012 แน่นอนคุณสามารถใช้ใหม่OFFSET/ FETCH NEXTไวยากรณ์:

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 

ควรสังเกตว่า OFFSET / FETCH NEXT นั้นไม่ได้ให้ประโยชน์ด้านประสิทธิภาพใด ๆ กับวิธีการ CTE
4324 Akash

2
@Aash คุณมีการทดสอบอย่างละเอียดนี้? ฉันสังเกตเห็นความแตกต่างของแผนบางอย่าง แต่ไม่ได้เอ่ยถึงอะไรเป็นพิเศษเกี่ยวกับประสิทธิภาพเพราะฉันยังไม่ได้ทำการทดสอบอย่างละเอียด แม้ว่าประสิทธิภาพการทำงานจะเหมือนกัน แต่ไวยากรณ์ก็ยุ่งยากน้อยกว่าเล็กน้อย ฉันทำบล็อกเกี่ยวกับที่นี่: sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10//
Aaron Bertrand

1
อาคุณพูดถูกและมีความแตกต่างด้านประสิทธิภาพ ผมได้อ่านบทความนี้: blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/...ที่เขากล่าวไม่แตกต่างกัน แต่เพียงเลื่อยchannel9.msdn.com/posts/SQL11UPD03-REC-02ที่เขาแสดงให้เห็นว่าเธอเอาใจใส่ ความแตกต่างมากมาย .. (แม้ว่าเสียงจะเน้นความแตกต่างของประสิทธิภาพ)
Akash

2

แม้ว่าคุณอาจไม่ทราบกลไกที่อยู่เบื้องหลัง แต่คุณสามารถทดสอบสิ่งนี้ได้ด้วยตัวเองโดยเปรียบเทียบประสิทธิภาพของข้อความค้นหาของคุณกับ: select * จาก Employee

SQL Server รุ่นที่ใหม่กว่าทำงานได้ดีที่สุดในการปรับ แต่มันก็ขึ้นอยู่กับหลายปัจจัย

การทำงานของ ROW_NUMBER ของคุณจะขับเคลื่อนโดยคำสั่งซื้อตามข้อ ในตัวอย่างของคุณส่วนใหญ่จะเดา EmpID เป็นคีย์หลัก

มีบางส่วนที่คำสั่งที่ซับซ้อนมากและ / หรือเขียนโค้ดหรือจัดทำดัชนีไม่ดีคุณอาจจะดีกว่าแค่ส่งคืนชุดข้อมูลทั้งหมด (มันหายากและสามารถแก้ไขได้) การใช้ระหว่างมีปัญหา

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


2

ฉันรู้ว่าคำถามเกี่ยวกับ row_number () แต่ฉันต้องการเพิ่มหนึ่งคุณลักษณะใหม่ของ sql server 2012 ใน sql server 2012 คุณสมบัติใหม่ OFFSET Fetch เปิดตัวถัดไปและมันเร็วกว่า row_number () ฉันใช้มันและมันให้ผลลัพธ์ที่ดีหวังว่าพวกคุณจะเติมประสบการณ์แบบเดียวกัน

ฉันพบตัวอย่างหนึ่งในhttp://blogfornet.com/2013/06/sql-server-2012-offset-use/

ซึ่งมีประโยชน์ หวังว่ามันจะช่วยคุณในการใช้คุณสมบัติใหม่ ๆ ด้วยเช่นกัน


-2

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


-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId

4
คุณสามารถขยายคำตอบของคุณ? คำถามก็คือว่าเพจจิ้งทำงานอย่างไรภายในกับ SQL Server - นั่นคือโปรแกรมฐานข้อมูลทำอะไรเพื่อตอบสนองการร้องขอ น่าเสียดายที่ ณ ตอนนี้คำตอบของคุณไม่ได้ตอบปัญหาที่แท้จริง
Mr.Brownstone
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.