Bagaimana cara menulis LINQ's .Skip (1000) .Take (100) dalam SQL murni?

93

Apa persamaan SQL dari .Skip()metode di LINQ?

Misalnya: Saya ingin memilih baris 1000-1100 dari tabel database tertentu.

Apakah ini mungkin hanya dengan SQL? Atau apakah saya perlu memilih seluruh tabel, lalu mencari baris di memori? Idealnya saya ingin menghindari ini, jika memungkinkan, karena mejanya bisa sangat besar.

sinar
sumber

Jawaban:

78

Di SQL Server 2005 ke atas, Anda dapat menggunakan fungsi ROW_NUMBER . misalnya.

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 51 AND 60; --BETWEEN is inclusive
Dan Diplo
sumber
Lihat tautan dalam jawaban saya untuk sedikit lebih detail. stackoverflow.com/questions/1744802/…
Mike Atlas
ANTARA 51 dan 60 - itu inklusif.
Drew Miller
1
Tapi ini pertama-tama akan memilih semua dan kemudian dari pilihan itu hanya mengambil 10 bukan? Atau akankah kueri / tampilan pertama hanya memiliki 10?
Tadej
139

SQL Server 2012 dan yang lebih baru telah menambahkan sintaks ini:

SELECT *
FROM Sales.SalesOrderHeader 
ORDER BY OrderDate
OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY
John Gietzen
sumber
11
Perhatikan bahwa Anda perlu menggunakan ORDER BY ___ untuk menggunakan perintah OFFSET .... bukan berarti Anda harus mencoba penomoran halaman tanpa perintah.
James Haug
Perhatikan juga bahwa sintaks 'baru' secara aneh memiliki penalti kinerja linier dengan @skip! Pendekatan row_number TIDAK memiliki ini (hanya diuji pada urutan yang diindeks). Untuk lo @Skip kurang sekitar 20, sintaks baru lebih cepat daripada pendekatan row_number.
Eske Rahn
22

LINQ ke SQL melakukan ini dengan menggunakan fungsi jendela ROW_NUMBER:

  SELECT a,b,c FROM 
   (SELECT a,b,c, ROW_NUMBER() OVER (ORDER BY ...) as row_number
    FROM Table) t0
   WHERE to.row_number BETWEEN 1000 and 1100;

Ini berfungsi, tetapi kebutuhan untuk membuat row_number dari ORDER BY dapat mengakibatkan kueri Anda diurutkan di sisi server dan menyebabkan masalah kinerja. Meskipun indeks dapat memenuhi persyaratan ORDER BY, kueri masih harus menghitung 1000 baris sebelum mulai mengembalikan hasil. Terlalu sering pengembang melupakan ini dan hanya melempar kontrol pagination ke tabel baris 5 juta dan bertanya-tanya mengapa halaman pertama dikembalikan jauh lebih cepat daripada yang terakhir ...

Meskipun demikian, menggunakan ROW_NUMBER () mungkin merupakan keseimbangan terbaik antara kemudahan penggunaan dan kinerja yang baik, asalkan Anda memastikan Anda menghindari pengurutan (kondisi ORDER BY dapat dipenuhi oleh indeks).

Remus Rusanu
sumber
1
Terima kasih atas info kinerja ekstra, harus berhati-hati dan mengujinya.
Ray
Diuji dan untuk tabel setengah juta baris saya, halaman terakhir itu sekitar 7 kali lebih lambat dari halaman pertama. Tidak ideal, tapi bisa diterima oleh saya.
Ray
6

Coba yang ini:

select * from [Table-Name] order by [Column-Name] 
offset [Skip-Count] rows
FETCH NEXT [Take-Count] rows only

Contoh:

select * from Personals order by Id
offset 10 rows            --------->Skip 10
FETCH NEXT 15 rows only   --------->Take 15
Fereydoon Barikzehy
sumber
4

Melakukan hal ini:

Jalankan .Skip (1000). Ambil (100) pada konteks data LINQ ke SQL dan lihat keluaran SQL. Ini akan menghasilkan pernyataan SQL untuk Anda yang melakukan apa yang Anda gambarkan.

Ini tidak akan seanggun tetapi menyelesaikan pekerjaan.

Joseph
sumber
2
Bukan apa yang diminta.
RayLoveless