Haruskah saya menggunakan LINQ Skip()
dan Take()
metode untuk paging, atau menerapkan paging saya sendiri dengan kueri SQL?
Mana yang paling efisien? Mengapa saya harus memilih salah satu dari yang lain?
Saya menggunakan SQL Server 2008, ASP.NET MVC, dan LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
StoneHeart
sumber
sumber
Jawaban:
Mencoba memberikan jawaban singkat atas keraguan Anda, jika Anda menjalankan
skip(n).take(m)
metode di linq (dengan SQL 2005/2008 sebagai server database) kueri Anda akan menggunakanSelect ROW_NUMBER() Over ...
pernyataan tersebut, dengan paging langsung di mesin SQL.Memberi Anda contoh, saya memiliki tabel db yang dipanggil
mtcity
dan saya menulis kueri berikut (bekerja juga dengan linq ke entitas):Kueri yang dihasilkan adalah:
Yang merupakan akses data berjendela (cukup keren, btw cuz akan mengembalikan data sejak awal dan akan mengakses tabel selama kondisi terpenuhi). Ini akan sangat mirip dengan:
Dengan pengecualian, query kedua ini akan dieksekusi lebih cepat daripada hasil linq karena akan menggunakan indeks secara eksklusif untuk membuat jendela akses data; ini berarti, jika Anda memerlukan beberapa pemfilteran, pemfilteran harus (atau harus) dalam daftar Entitas (tempat baris dibuat) dan beberapa indeks harus dibuat juga untuk menjaga kinerja yang baik.
Sekarang, apa yang lebih baik?
Jika Anda memiliki cukup banyak alur kerja yang solid dalam logika Anda, menerapkan cara SQL yang tepat akan menjadi rumit. Dalam hal ini LINQ akan menjadi solusinya.
Jika Anda dapat menurunkan bagian logika itu langsung ke SQL (dalam prosedur tersimpan), itu akan menjadi lebih baik karena Anda dapat mengimplementasikan kueri kedua yang saya tunjukkan (menggunakan indeks) dan mengizinkan SQL untuk menghasilkan dan menyimpan Rencana Eksekusi dari query (meningkatkan kinerja).
sumber
Coba gunakan
untuk mendapatkan baris dari 501 hingga 600 di server SQL, tanpa memuatnya ke memori. Perhatikan bahwa sintaks ini telah tersedia dengan SQL Server 2012 hanya
sumber
Meskipun LINQ-to-SQL akan menghasilkan
OFFSET
klausa (mungkin ditiru menggunakanROW_NUMBER() OVER()
seperti yang disebutkan orang lain ), ada cara yang sama sekali berbeda dan jauh lebih cepat untuk melakukan paging dalam SQL. Ini sering disebut "metode pencarian" seperti yang dijelaskan dalam posting blog ini di sini .Nilai
@previousScore
dan@previousPlayerId
adalah nilai masing-masing dari catatan terakhir dari halaman sebelumnya. Ini memungkinkan Anda untuk mengambil halaman "berikutnya". JikaORDER BY
arahnya adalahASC
, gunakan>
saja.Dengan metode di atas, Anda tidak bisa langsung melompat ke halaman 4 tanpa terlebih dahulu mengambil 40 record sebelumnya. Namun seringkali, Anda tidak ingin melompat sejauh itu. Sebaliknya, Anda mendapatkan kueri yang jauh lebih cepat yang mungkin dapat mengambil data dalam waktu yang konstan, bergantung pada pengindeksan Anda. Plus, halaman Anda tetap "stabil", tidak peduli apakah data dasarnya berubah (mis. Di halaman 1, sementara Anda di halaman 4).
Ini adalah cara terbaik untuk mengimplementasikan paging saat malas memuat lebih banyak data di aplikasi web, misalnya.
Catatan, "metode pencarian" juga disebut paging keyset .
sumber
LinqToSql secara otomatis akan mengubah .Skip (N1) .Take (N2) menjadi sintaks TSQL untuk Anda. Faktanya, setiap "kueri" yang Anda lakukan di Linq, sebenarnya hanya membuat kueri SQL untuk Anda di latar belakang. Untuk mengujinya, jalankan saja SQL Profiler saat aplikasi Anda sedang berjalan.
Metodologi lewati / ambil telah bekerja dengan sangat baik untuk saya, dan orang lain dari apa yang saya baca.
Karena penasaran, jenis query self-paging apa yang Anda miliki, yang menurut Anda lebih efisien daripada skip / take Linq?
sumber
Kami menggunakan CTE yang dibungkus dengan SQL Dinamis (karena aplikasi kami memerlukan pengurutan dinamis dari sisi server data) dalam prosedur yang tersimpan. Saya dapat memberikan contoh dasar jika Anda mau.
Saya belum sempat melihat T / SQL yang dihasilkan LINQ. Bisakah seseorang memposting sampel?
Kami tidak menggunakan LINQ atau akses langsung ke tabel karena kami memerlukan lapisan keamanan ekstra (diberikan SQL dinamis agak memecah ini).
Sesuatu seperti ini seharusnya berhasil. Anda dapat menambahkan nilai parameter untuk parameter, dll.
sumber
sp_executesql
Anda memiliki kemungkinan untuk melewati parameter dengan cara yang aman, misalnya:EXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. Aman dalam konteks ini berarti kuat terhadap injeksi SQL - Anda dapat meneruskan setiap kemungkinan nilai di dalam variabel@ValueForCol4
- bahkan'--'
, dan kueri akan tetap berfungsi!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
emulasi offset. Lihat juga: 4guysfromrolla.com/webtech/042606-1.shtmlDi SQL Server 2008:
Di t0 semua record Di t1 hanya yang sesuai dengan halaman itu
sumber
Pendekatan yang saya berikan adalah pagination tercepat yang dapat dicapai SQL server. Saya telah menguji ini pada 5 juta catatan. Pendekatan ini jauh lebih baik daripada "OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY" yang disediakan oleh SQL Server.
sumber
Anda dapat lebih meningkatkan kinerja, cek ini
jika Anda akan menggunakan dari dengan cara ini akan memberikan hasil yang lebih baik:
alasan: karena Anda menggunakan kelas where pada tabel CityEntities yang akan menghilangkan banyak rekaman sebelum bergabung dengan MtCity, jadi 100% yakin itu akan meningkatkan kinerja berkali-kali lipat ...
Pokoknya jawaban rodrigoelp sangat membantu.
Terima kasih
sumber
@p0
dan lebih tepatnya@p1
berasalAnda bisa mengimplementasikan paging dengan cara sederhana ini dengan meneruskan PageIndex
sumber
Pada tahun 2008 kami tidak dapat menggunakan Skip (). Take ()
Caranya adalah:
sumber