2010-02-22 18 views
13

Tôi muốn thực hiện bảng phân trang sử dụng phương pháp này:Có vấn đề về hiệu suất nào khi sử dụng Row_Number để triển khai phân trang bảng trong Sql Server 2008 không?

SET @PageNum = 2; 
SET @PageSize = 10; 

WITH OrdersRN AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS RowNum 
      ,* 
     FROM dbo.Orders 
) 

SELECT * 
    FROM OrdersRN 
WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1 
        AND @PageNum * @PageSize 
ORDER BY OrderDate ,OrderID; 

Có điều gì tôi cần phải nhận thức? Bảng có hàng triệu hồ sơ.

Thx.

EDIT: Sau khi sử dụng gợi ý MAXROWS phương pháp trong một thời gian (trong đó hoạt động thực sự rất nhanh) Tôi đã phải chuyển về ROW_NUMBER phương pháp vì sự linh hoạt hơn của nó. Tôi cũng rất hài lòng về tốc độ của nó cho đến nay (Tôi đang làm việc với View có nhiều hơn 1 triệu hồ sơ với 10 cột). Để sử dụng bất kỳ loại truy vấn nào tôi sử dụng sửa đổi sau đây:

PROCEDURE [dbo].[PageSelect] 
(
    @Sql nvarchar(512), 
    @OrderBy nvarchar(128) = 'Id', 
    @PageNum int = 1, 
    @PageSize int = 0  
) 
AS 
BEGIN 
SET NOCOUNT ON 

Declare @tsql as nvarchar(1024) 
Declare @i int, @j int 

if (@PageSize <= 0) OR (@PageSize > 10000) 
    SET @PageSize = 10000 -- never return more then 10K records 

SET @i = (@PageNum - 1) * @PageSize + 1 
SET @j = @PageNum * @PageSize 

SET @tsql = 
'WITH MyTableOrViewRN AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY ' + @OrderBy + ') AS RowNum 
    ,* 
    FROM MyTableOrView 
    WHERE ' + @Sql + ' 

) 
SELECT * 
    FROM MyTableOrViewRN 
    WHERE RowNum BETWEEN ' + CAST(@i as varchar) + ' AND ' + cast(@j as varchar) 

exec(@tsql) 
END 

Nếu bạn sử dụng quy trình này, hãy chắc chắn rằng bạn đã ngăn chặn tiêm sql.

+0

Trùng lặp chính xác: http://stackoverflow.com/questions/1897436/row-number-over-not-fast-enough-with-large-result-set-any-good-solution –

+0

Pony, tôi không phải là rất hài lòng với câu trả lời đó, chủ yếu là bởi vì nó thậm chí không đề cập đến Row_Number() ..... Câu hỏi đặt ra, một lần nữa: Tôi đang sử dụng Row_Number().Những gì bạn có thể cho tôi biết về hiệu quả của nó so với một phương pháp khác (vì vậy, không cung cấp cho tôi một phương pháp khác) – majkinetor

+2

BTW, Pony Tôi nhận xét như thế này rất thô lỗ. Tôi chắc rằng tôi biết câu trả lời hay cho câu hỏi của tôi là gì, tôi không cần phải nói với tôi điều đó. Amdin BS điển hình. – majkinetor

Trả lời

19

Tôi đã viết về điều này một vài lần thực sự; ROW_NUMBER đến nay là linh hoạt nhất và dễ sử dụng, và hiệu suất là tốt, nhưng đối với dữ liệu rất lớn đặt ra nó không phải là lúc nào cũng là tốt nhất . SQL Server vẫn cần sắp xếp dữ liệu và sắp xếp có thể khá tốn kém.

Có một số different approach here sử dụng một vài biến và SET ROWCOUNT và cực kỳ nhanh, miễn là bạn có chỉ mục phù hợp. Đó là cũ, nhưng theo như tôi biết, nó vẫn là hiệu quả nhất. Về cơ bản, bạn có thể làm một cách hoàn toàn ngây thơ SELECT với SET ROWCOUNT và SQL Server có thể tối ưu hóa hầu hết công việc thực tế; kế hoạch và chi phí kết thúc tương tự như hai truy vấn MAX/MIN, thường nhanh hơn rất nhiều so với truy vấn cửa sổ đơn. Đối với các tập dữ liệu rất lớn, điều này chạy dưới 1/10 thời gian.

Có nói rằng, tôi vẫn luôn khuyên bạn nên ROW_NUMBER khi mọi người hỏi về cách triển khai những thứ như phân trang hoặc tối đa theo nhóm, vì mức độ dễ sử dụng. Tôi sẽ chỉ bắt đầu xem xét các lựa chọn thay thế như trên nếu bạn bắt đầu nhận thấy sự chậm lại với ROW_NUMBER.

+0

Câu trả lời có thể chấp nhận đầu tiên. Cảm ơn m8. Tôi không cần tốt nhất của tốt nhất. Tôi cần tốt. – majkinetor

+0

Tôi đã sử dụng phương pháp này với ROWCOUNT và tôi rất hài lòng với nó, nó cực kỳ nhanh. Tuy nhiên, tôi không thể làm cho nó hoạt động khi tôi có câu lệnh ORDER BY tùy chỉnh với các cột không nhận dạng. Bạn có biết một cách xung quanh nó? – majkinetor

+0

@majkinetor: Bạn có ý đơn giản là bạn muốn sắp xếp/trang của một trường khác với ID, hoặc bảng không có cột ID hoặc khóa tuần tự nào cả? – Aaronaught

8

Gần đây, tôi sử dụng phân trang trong một môi trường kho dữ liệu với một schema sao. Tôi thấy rằng hiệu suất rất tốt khi tôi hạn chế CTE chỉ truy vấn các hàng cần thiết để xác định ROW_NUMBER. Tôi đã có CTE trả về ROW_NUMBER cộng với các khóa chính của các hàng khác đã giúp xác định số hàng.

Trong truy vấn chính, tôi đã tham chiếu ROW_NUMBER để phân trang và sau đó tham gia vào các bảng khác dựa trên các khóa chính khác từ CTE. Tôi thấy rằng các phép nối chỉ được thực hiện trên các hàng thỏa mãn mệnh đề WHERE trong truy vấn bên ngoài, tiết kiệm rất nhiều thời gian.

+0

Tôi chỉ có một bảng duy nhất. – majkinetor

+1

Điều đó sẽ làm cho nó thậm chí còn ít hơn của một vấn đề. Hãy thử nó, sau đó nhìn vào kế hoạch thực hiện. –

+0

Thx cho ý kiến ​​của bạn. – majkinetor

-2

kiểm tra giải pháp này, có thể nó tốt hơn. thay đổi điều này với nhu cầu của bạn.

CREATE PROCEDURE sp_PagedItems 
    (
    @Page int, 
    @RecsPerPage int 
    ) 
AS 

-- We don't want to return the # of rows inserted 
-- into our temporary table, so turn NOCOUNT ON 
SET NOCOUNT ON 


--Create a temporary table 
CREATE TABLE #TempItems 
(
    ID int IDENTITY, 
    Name varchar(50), 
    Price currency 
) 


-- Insert the rows from tblItems into the temp. table 
INSERT INTO #TempItems (Name, Price) 
SELECT Name,Price FROM tblItem ORDER BY Price 

-- Find out the first and last record we want 
DECLARE @FirstRec int, @LastRec int 
SELECT @FirstRec = (@Page - 1) * @RecsPerPage 
SELECT @LastRec = (@Page * @RecsPerPage + 1) 

-- Now, return the set of paged records, plus, an indiciation of we 
-- have more records or not! 
SELECT *, 
     MoreRecords = 
    (
    SELECT COUNT(*) 
    FROM #TempItems TI 
    WHERE TI.ID >= @LastRec 
    ) 
FROM #TempItems 
WHERE ID > @FirstRec AND ID < @LastRec 


-- Turn NOCOUNT back OFF 
SET NOCOUNT OFF 
+1

Sao chép toàn bộ bảng vào bảng tạm thời ... không có chỉ mục? Yeah, sẽ chậm thôi. Reeeeal chậm. Khó tưởng tượng một cách tiếp cận tồi tệ hơn, TBH. – Aaronaught

+0

Ngoài ra, hãy lưu ý vấn đề "Row_Number" trong câu hỏi. Mặc dù tôi không tìm thấy điều này hữu ích (không có hành vi phạm tội), tôi sẽ cung cấp cho bạn một lợi thế chỉ để làm cho OMG Ponnies và bạn bè của mình hạnh phúc. – majkinetor

+1

Tôi viết thư này cho bạn để giúp đỡ một người. :) –

Các vấn đề liên quan