Bagaimana cara kerja paging dengan ROW_NUMBER di SQL Server?

13

Saya memiliki Employeetabel yang memiliki satu juta catatan. Saya telah mengikuti SQL untuk paging data dalam aplikasi web. Ini bekerja dengan baik. Namun apa yang saya lihat sebagai masalah adalah - tabel turunan tblEmployeememilih semua rekaman dalam Employeetabel (untuk membuat MyRowNumbernilai).

Saya pikir, ini menyebabkan pemilihan semua catatan dalam Employeetabel.

Apakah ini benar-benar berfungsi? Atau SQL Server dioptimalkan untuk memilih hanya 5 catatan dari Employeetabel asli juga?

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 
LCJ
sumber
3
Lihat sqlservercentral.com/articles/T-SQL/66030 dan yang lebih penting adalah diskusi berikutnya .
Aaron Bertrand

Jawaban:

17

Alternatif untuk menguji mungkin:

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

Ya, Anda menekan tabel dua kali, tetapi di CTE di mana Anda memindai seluruh tabel Anda hanya meraih kunci, bukan SEMUA data. Tetapi Anda benar-benar harus melihat artikel ini:

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

Dan diskusi lanjutan:

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

Dalam SQL Server 2012 tentu saja Anda dapat menggunakan OFFSET/ FETCH NEXTsintaks baru:

;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 ...; 
Aaron Bertrand
sumber
Namun perlu dicatat bahwa OFFSET / FETCH NEXT tidak menawarkan manfaat kinerja apa pun atas metode CTE
Akash
2
@Akash sudahkah Anda menguji ini dengan seksama? Saya telah mengamati beberapa perbedaan rencana tetapi tidak secara khusus menyebutkan apa pun tentang kinerja karena saya belum melakukan pengujian ekstensif. Bahkan jika kinerjanya sama, sintaksisnya sedikit kurang rumit. Saya membuat blog tentang itu di sini: sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/…
Aaron Bertrand
1
Ah, Anda benar, ada perbedaan kinerja. Saya telah membaca ini: blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/… di mana ia menyebutkan tidak ada perbedaan, tetapi hanya melihat channel9.msdn.com/posts/SQL11UPD03-REC-02 di mana ia menunjukkan theres banyak perbedaan .. (meskipun dalam audio kurang menekankan perbedaan kinerja)
Akash
2

Meskipun Anda mungkin tidak tahu mekanisme di baliknya, Anda dapat mengujinya sendiri dengan membandingkan kinerja kueri Anda dengan: pilih * dari Karyawan.

Versi terbaru dari SQL Server melakukan pekerjaan yang cukup baik untuk mengoptimalkan, tetapi dapat bergantung pada beberapa faktor.

Bagaimana kinerja fungsi ROW_NUMBER Anda akan didorong oleh klausa Pesanan Menurut. Dalam contoh Anda, sebagian besar akan menebak EmpID adalah kunci utama.

Ada beberapa di mana klausul yang begitu kompleks dan / atau kode buruk atau diindeks, Anda mungkin akan lebih baik hanya mengembalikan seluruh dataset (itu langka dan bisa diperbaiki). Menggunakan ANTARA memiliki masalah.

Sebelum Anda menganggap akan lebih baik untuk mengembalikan semua baris ke aplikasi Anda dan membiarkannya mengetahuinya, Anda harus berupaya mengoptimalkan kueri Anda. Periksa estimasi. Tanyakan Query Analyzer. Uji beberapa alternatif.

JeffO
sumber
2

Saya tahu pertanyaannya adalah tentang row_number () tetapi saya ingin menambahkan satu fitur baru dari sql server 2012. Dalam sql server 2012 fitur baru OFFSET Ambil berikutnya yang diperkenalkan dan sangat cepat daripada row_number (). Saya sudah menggunakannya dan itu memberi saya hasil yang baik berharap kalian juga mengisi pengalaman yang sama.

Saya menemukan satu contoh di http://blogfornet.com/2013/06/sql-server-2012-offset-use/

yang bermanfaat. Semoga ini akan membantu Anda juga untuk mengimplementasikan fitur-fitur baru ....

Sam Raj
sumber
-2

Saya tidak berpikir itu mengevaluasi untuk mengembalikan semua baris di tabel asli. SQL server mengoptimalkan. Kalau tidak, akan membutuhkan banyak waktu untuk memilih satu juta entri. Saat ini saya menggunakan ini dan itu jauh lebih cepat daripada memilih semua baris. Jadi, pasti tidak mendapatkan semua baris. Namun itu lebih lambat daripada hanya mengambil lima baris pertama, mungkin karena waktu yang dibutuhkan untuk memesan

pengguna3688672
sumber
-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
Agnel Amodia
sumber
4
Bisakah Anda memperluas jawaban Anda? Pertanyaannya adalah tentang bagaimana paging bekerja secara internal ke SQL Server - yaitu apa yang dilakukan mesin database untuk memenuhi permintaan. Sayangnya, sampai sekarang, jawaban Anda tidak membahas masalah yang sebenarnya.
Mr.Brownstone