Model baru OFFSET ... FETCH
yang diperkenalkan dengan SQL Server 2012 menawarkan paging yang sederhana dan lebih cepat. Mengapa ada perbedaan sama sekali mengingat kedua bentuk itu secara semantik identik dan sangat umum?
Orang akan berasumsi bahwa optimizer mengenali keduanya dan mengoptimalkannya (sepele) sepenuhnya.
Berikut ini adalah kasus yang sangat sederhana di mana OFFSET ... FETCH
~ 2x lebih cepat sesuai dengan perkiraan biaya.
SELECT * INTO #objects FROM sys.objects
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY object_id) r
FROM #objects
) x
WHERE r >= 30 AND r < (30 + 10)
ORDER BY object_id
SELECT *
FROM #objects
ORDER BY object_id
OFFSET 30 ROWS FETCH NEXT 10 ROWS ONLY
Satu dapat memvariasikan test case ini dengan membuat CI pada object_id
atau menambahkan filter tetapi tidak mungkin untuk menghapus semua perbedaan rencana. OFFSET ... FETCH
selalu lebih cepat karena itu kurang bekerja pada waktu eksekusi.
Jawaban:
Contoh-contoh dalam pertanyaan tidak cukup menghasilkan hasil yang sama (
OFFSET
contoh memiliki kesalahan off-by-one). Formulir yang diperbarui di bawah memperbaiki masalah itu, menghapus jenis tambahan untukROW_NUMBER
kasus ini, dan menggunakan variabel untuk membuat solusi lebih umum:Paket
ROW_NUMBER
tersebut memiliki perkiraan biaya 0,0197935 :Paket
OFFSET
tersebut memiliki perkiraan biaya 0,0196955 :Itu adalah penghematan 0,000098 unit biaya yang diperkirakan (meskipun
OFFSET
paket tersebut akan membutuhkan operator tambahan jika Anda ingin mengembalikan nomor baris untuk setiap baris). ItuOFFSET
rencana masih akan sedikit lebih murah, secara umum, tapi ingat bahwa estimasi biaya persis bahwa - pengujian nyata masih diperlukan. Sebagian besar biaya dalam kedua paket adalah biaya jenis input yang lengkap, sehingga indeks yang bermanfaat akan menguntungkan kedua solusi.Di mana nilai literal konstan digunakan (misalnya
OFFSET 30
dalam contoh asli) pengoptimal dapat menggunakan Sortasi TopN alih-alih pengurutan lengkap diikuti oleh Top. Ketika baris yang diperlukan dari Sort TopN adalah literal konstan dan <= 100 (jumlahOFFSET
danFETCH
) mesin eksekusi dapat menggunakan algoritma sort yang berbeda yang dapat melakukan lebih cepat daripada sortasi TopN yang digeneralisasi. Ketiga kasus memiliki karakteristik kinerja yang berbeda secara keseluruhan.Mengapa pengoptimal tidak secara otomatis mengubah
ROW_NUMBER
pola sintaksis untuk digunakanOFFSET
, ada beberapa alasan:OFFSET
rencana tidak dijamin untuk menjadi lebih baik dalam semua kasusSalah satu contoh untuk titik ketiga di atas terjadi di mana set paging cukup lebar. Ini bisa menjadi jauh lebih efisien untuk mencari kunci yang diperlukan menggunakan indeks nonclustered dan pencarian secara manual terhadap indeks berkerumun dibandingkan dengan memindai indeks dengan
OFFSET
atauROW_NUMBER
. Ada masalah tambahan untuk dipertimbangkan jika aplikasi paging perlu tahu berapa banyak baris atau halaman yang ada secara total. Ada diskusi bagus lainnya tentang manfaat relatif dari metode 'pencarian kunci' dan 'offset' di sini .Secara keseluruhan, mungkin lebih baik bahwa orang membuat keputusan untuk mengubah permintaan halaman mereka
OFFSET
, jika perlu, setelah pengujian menyeluruh.sumber
Dengan sedikit mengutak-atik kueri Anda, saya mendapatkan taksiran biaya yang sama (50/50) dan statistik IO yang sama:
Ini menghindari pengurutan tambahan yang muncul di versi Anda dengan mengurutkan
r
alih-alihobject_id
.sumber
r
daripada kolom dasar, jika hanya karena cocok dengan apa yang akan saya lakukan dalam permintaan non-bersarang dan memesan dengan ekspresi - Saya akan menggunakan alias yang ditugaskan untuk ekspresi alih-alih mengulangi ekspresi.Mereka memodifikasi pengoptimal kueri untuk menambahkan fitur ini. Berarti mereka menerapkan mekanisme khusus untuk mendukung perintah offset ... fetch. Dengan kata lain untuk permintaan teratas SQL Server harus melakukan lebih banyak pekerjaan. Demikian perbedaan dalam rencana kueri.
sumber