Làm thế nào để phân trang hoạt động với ROW_NUMBER trong SQL Server?


13

Tôi có một Employeebảng có một triệu hồ sơ. Tôi đã theo SQL để phân trang dữ liệu trong một ứng dụng web. Nó đang hoạt động tốt. Tuy nhiên, điều tôi thấy là một vấn đề là - bảng dẫn xuất tblEmployeechọn tất cả các bản ghi trong Employeebảng (để tạo các MyRowNumbergiá trị).

Tôi nghĩ rằng, điều này gây ra sự lựa chọn của tất cả các hồ sơ trong Employeebảng.

Nó thực sự làm việc như vậy? Hoặc SQL Server được tối ưu hóa để chỉ chọn 5 bản ghi từ Employeebảng gốc ?

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 

Câu trả lời:


17

Một cách khác để kiểm tra có thể là:

;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 ...;

Có, bạn nhấn bảng hai lần, nhưng trong CTE nơi bạn quét toàn bộ bảng, bạn chỉ lấy được chìa khóa, không phải TẤT CẢ dữ liệu. Nhưng bạn thực sự nên xem bài viết này:

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

Và các cuộc thảo luận tiếp theo:

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

Trong SQL Server 2012 tất nhiên bạn có thể sử dụng cú pháp OFFSET/ mới 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 ...; 

Tuy nhiên, cần lưu ý rằng OFFSET / FETCH NEXT không cung cấp bất kỳ lợi ích hiệu suất nào so với phương pháp CTE
Akash

2
@Akash bạn đã kiểm tra kỹ lưỡng điều này chưa? Tôi đã quan sát một số khác biệt về kế hoạch nhưng không đề cập cụ thể bất cứ điều gì về hiệu suất vì tôi chưa thực hiện bất kỳ thử nghiệm mở rộng nào. Ngay cả khi hiệu suất là như nhau, cú pháp hơi ít cồng kềnh. Tôi đã viết blog về nó ở đây: sqlblog.com/bloss/aaron_bertrand/archive/2010/11/10/ mẹo
Aaron Bertrand

1
Ah, bạn nói đúng, có sự khác biệt về hiệu suất. Tôi đã đọc: blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/... nơi ông đề cập đến có sự khác biệt, nhưng chỉ cần cưa channel9.msdn.com/posts/SQL11UPD03-REC-02 nơi ông thấy theres rất nhiều sự khác biệt .. (mặc dù trong âm thanh nhấn mạnh đến sự khác biệt về hiệu suất)
Akash

2

Mặc dù bạn có thể không biết cơ chế đằng sau nó, nhưng bạn có thể tự kiểm tra điều này bằng cách so sánh hiệu suất của truy vấn của bạn với: select * từ Nhân viên.

Các phiên bản gần đây hơn của SQL Server thực hiện công việc tối ưu hóa khá tốt, nhưng nó có thể phụ thuộc vào một số yếu tố.

Cách hàm ROW_NUMBER của bạn thực hiện sẽ được điều khiển bởi mệnh đề Order By. Trong ví dụ của bạn, hầu hết sẽ đoán EmpID là khóa chính.

Có một số nơi điều khoản đó rất phức tạp và / hoặc kém mã hóa hoặc lập chỉ mục, bạn có thể được tốt hơn off chỉ trả lại toàn bộ dữ liệu (đó là hiếm và có thể được cố định). Sử dụng GIỮA có vấn đề.

Trước khi bạn cho rằng sẽ tốt hơn là trả lại tất cả các hàng cho ứng dụng của bạn và để nó tìm ra nó, bạn nên làm việc để tối ưu hóa truy vấn của mình. Kiểm tra các ước tính. Hỏi người phân tích truy vấn. Kiểm tra một số lựa chọn thay thế.


2

Tôi biết câu hỏi liên quan đến row_number () nhưng tôi muốn thêm một tính năng mới của máy chủ sql 2012. Trong máy chủ sql 2012 tính năng mới của OFFSET Fetch được giới thiệu tiếp theo và nó rất nhanh hơn row_number (). Tôi đã sử dụng nó và nó mang lại cho tôi kết quả tốt với hy vọng các bạn cũng điền vào cùng một kinh nghiệm.

Tôi đã tìm thấy một ví dụ trên http://blogfornet.com/2013/06/sql-server-2012-offset-use/

cái nào hữu ích Hy vọng nó sẽ giúp bạn quá để thực hiện các tính năng mới ....


-2

Tôi không nghĩ rằng nó đánh giá để trả về tất cả các hàng trong bảng gốc. Máy chủ SQL tối ưu hóa. Nếu không, sẽ mất một lượng lớn thời gian để chọn một triệu mục. Tôi hiện đang sử dụng cái này và nó nhanh hơn nhiều so với việc chọn tất cả các hàng. Vì vậy, chắc chắn không nhận được tất cả các hàng. Tuy nhiên, nó chậm hơn so với việc chỉ tìm nạp năm hàng đầu tiên, có thể là do thời gian thực hiện theo thứ tự


-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
Bạn có thể mở rộng câu trả lời của bạn? Câu hỏi liên quan đến cách phân trang hoạt động nội bộ với SQL Server - tức là công cụ cơ sở dữ liệu làm gì để thực hiện yêu cầu. Thật không may, như bây giờ, câu trả lời của bạn không giải quyết mối quan tâm thực sự.
Mr.Brownstone
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.