Pagination dalam SQL Server


17

Saya memiliki basis data yang sangat besar, sekitar 100 GB. Saya menjalankan kueri:

select * from <table_name>;

dan saya hanya ingin menampilkan baris ke 100 hingga 200.

Saya ingin memahami bagaimana ini terjadi secara internal. Apakah database mengambil semua catatan dari disk ke dalam memori dan mengirim kembali baris ke-100 ke 400 ke klien kueri? Atau apakah ada mekanisme, sehingga hanya catatan tersebut (100-200) yang diambil dari database - dengan menggunakan mekanisme pengindeksan seperti B-tree dll?

Saya menemukan bahwa ini terkait dengan konsep pagination, tetapi saya tidak dapat menemukan dengan tepat bagaimana hal itu terjadi secara internal di tingkat basis data.

Jawaban:


37

Dalam kueri yang Anda poskan:

select * from <table_name>;

Tidak ada yang namanya baris 100th-200th, karena Anda tidak menentukan ORDER BY. Pesanan tidak dijamin kecuali Anda menyertakan ORDER OLEH untuk banyak alasan menarik, tapi itu bukan intinya di sini.

Jadi untuk mengilustrasikan poin Anda, mari kita gunakan tabel - Saya akan menggunakan tabel Users dari dump data Stack Overflow , dan jalankan kueri ini:

SELECT * FROM dbo.Users ORDER BY DisplayName;

Secara default, tidak ada indeks pada bidang DisplayName, jadi SQL Server harus memindai seluruh tabel, lalu mengurutkannya dengan DisplayName. Inilah rencana pelaksanaannya :

Pemindaian indeks berkelompok dengan semacam

Ini tidak cantik - itu banyak pekerjaan, dengan perkiraan biaya subtree sekitar 30rb. (Anda dapat melihatnya dengan mengarahkan mouse ke operator pilih di PasteThePlan.) Jadi apa yang terjadi jika kita hanya ingin baris 100-200? Kita bisa menggunakan sintaks ini di SQL Server 2012+:

SELECT * FROM dbo.Users ORDER BY DisplayName OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY;

Rencana pelaksanaannya juga sangat jelek:

Pemindaian indeks berkelompok dengan sortir dan top

SQL Server masih memindai seluruh tabel untuk membangun daftar yang diurutkan hanya untuk memberi Anda baris 100-200, dan biayanya masih sekitar 30k. Lebih buruk lagi, seluruh daftar ini akan dibangun kembali setiap kali kueri Anda berjalan (karena bagaimanapun, seseorang mungkin telah mengubah DisplayName mereka.)

Untuk membuatnya berjalan lebih cepat, kita dapat membuat indeks nonclustered pada DisplayName, yang merupakan salinan tabel kami, diurutkan berdasarkan bidang tertentu:

CREATE INDEX IX_DisplayName ON dbo.Users(DisplayName);

Dengan indeks itu, rencana eksekusi permintaan kami sekarang melakukan pencarian indeks:

Pencarian indeks dan pencarian kunci

Kueri selesai secara instan dan diperkirakan memiliki biaya subtree hanya 0,66 (dibandingkan dengan 30k).

Singkatnya, jika Anda mengatur data dengan cara yang mendukung kueri yang sering Anda jalankan, maka ya, SQL Server bisa mengambil jalan pintas untuk membuat kueri Anda berjalan lebih cepat. Jika, di sisi lain, yang Anda miliki hanyalah tumpukan atau indeks berkerumun, Anda kacau.


"Secara default, tidak ada indeks pada bidang DisplayName, jadi SQL Server harus memindai seluruh tabel, lalu mengurutkannya dengan DisplayName." Maafkan saya jika ini adalah pertanyaan yang sangat mendasar - dalam kasus yang saya kutip dari jawaban Anda, Ketika Anda berkata "Pindai seluruh tabel", apakah itu berarti semua data dibawa ke dalam memori dan disortir (yang tidak terlihat seperti cara yang benar)?
AV94

Dari jawaban Anda, saya mengerti bahwa jika bidang diindeks, maka membuat pertanyaan seperti - mendapatkan baris ke 100 hingga 200 sangat efisien karena SQL mencari indeks (B-tree dll) dan langsung menuju ke titik itu (baris ke-100). Bisakah Anda memberi tahu saya jika ini pemahaman yang benar?
AV94

@AnilVedala tentang pertanyaan pertama Anda - ya, data harus disortir. Bagaimana lagi yang bisa dicapai oleh database dengan daftar yang tidak disortir?
Brent Ozar

1
@AnilVedala tentang pertanyaan kedua Anda - di situlah rencana eksekusi terakhir yang saya berikan kepada Anda. (Jika Anda bertanya tentang cara membaca rencana eksekusi, ambil buku Rencana Eksekusi oleh Grant Fritchey.)
Brent Ozar

15

Sama seperti tambahan untuk jawaban Brent saat menggunakan indeks yang tidak mencakup untuk menghindari semacam, ada masalah potensial dengan nomor halaman kemudian yang dapat dilihat dari menjalankan di bawah ini

SELECT * 
FROM dbo.Users 
ORDER BY DisplayName 
OFFSET 100000 ROWS 
FETCH NEXT 100 ROWS ONLY;

Rencana eksekusi menunjukkan bahwa pencarian dieksekusi 100.100 kali meskipun semua kecuali 100 baris kemudian disaring oleh operator TOP.

masukkan deskripsi gambar di sini

Ini dapat dikurangi dengan menggunakan pola di bawah ini

WITH T
     AS (SELECT Id,
                DisplayName
         FROM   dbo.Users
         ORDER  BY DisplayName
        OFFSET 100000 ROWS 
        FETCH NEXT 100 ROWS ONLY
        )
SELECT U.*
FROM   dbo.Users U
       JOIN T
         ON U.Id = T.Id
ORDER  BY T.DisplayName 

Ini menyaring semua kecuali 100 baris terakhir sebelum melakukan pencarian yang dapat memiliki dampak signifikan pada kecepatan untuk nilai offset yang besar.

masukkan deskripsi gambar di sini


3

Itu benar-benar tergantung pada bagaimana Anda menerapkan pagination dalam permintaan Anda, sifat data dan cara sistem Anda dikonfigurasi. Cukup aman untuk mengatakan bahwa SQL Server akan berusaha mengembalikan data Anda menggunakan apa yang dirasakan sebagai upaya seminimal mungkin. Jika Anda tidak memiliki urutan penyortiran, pemfilteran, pengelompokan, atau jendela apa pun secara eksplisit, SQL Server mungkin dapat mengoptimalkan paket kueri sehingga hanya dapat mengembalikan halaman dari disk yang berisi data yang diperlukan oleh kueri Anda - atau bahkan lebih baik, langsung dari kolam penyangga. Segera setelah Anda mulai mengubah kueri untuk menyertakan pengurutan, pengelompokan, jendela dan pemfilteran maka itu mulai menjadi rumit.

Ada artikel yang sangat bagus tentang Kinerja SQL di sini yang masuk ke beberapa detail dari berbagai metode pagination dan bagaimana mereka mempengaruhi rencana permintaan. Saya akan sangat merekomendasikan membacanya dan kemudian mencoba beberapa metode yang mereka tunjukkan dan melihat rencana permintaan apa yang dipilih pada sistem Anda sendiri.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.