Bagaimana (dan mengapa) TOP mempengaruhi rencana eksekusi?

35

Untuk kueri yang cukup rumit yang saya coba optimalkan, saya perhatikan bahwa menghapus TOP nklausa mengubah rencana eksekusi. Saya akan menduga bahwa ketika sebuah kueri memasukkan TOP nmesin basis data akan menjalankan kueri mengabaikan TOPklausa, dan kemudian pada akhirnya hanya mengecilkan hasil yang ditetapkan ke n jumlah baris yang diminta. Rencana eksekusi grafis tampaknya mengindikasikan hal ini - TOPadalah langkah "terakhir". Tetapi tampaknya ada lebih banyak hal yang terjadi.

Pertanyaan saya adalah, bagaimana (dan mengapa) klausa TOP n berdampak pada rencana eksekusi permintaan?

Berikut ini adalah versi sederhana dari apa yang terjadi dalam kasus saya:

Kueri mencocokkan baris dari dua tabel, A dan B.

Tanpa TOPklausa, pengoptimal memperkirakan akan ada 19k baris dari tabel A dan 46k baris dari tabel B. Jumlah aktual baris yang dikembalikan adalah 16k untuk A dan 13k untuk B. Kecocokan hash digunakan untuk menggabungkan dua set hasil ini untuk total 69 baris (kemudian diterapkan semacam). Permintaan ini terjadi dengan sangat cepat.

Ketika saya menambahkan TOP 1001pengoptimal tidak menggunakan kecocokan hash; sebagai gantinya ia mengurutkan hasil dari tabel A (estimasi yang sama / aktual 19k / 16k) dan melakukan loop bersarang terhadap tabel B. Perkiraan jumlah baris untuk tabel B sekarang 1, dan yang aneh adalah bahwa TOP nsecara langsung mempengaruhi perkiraan jumlah eksekusi (pencarian indeks) terhadap B - sepertinya selalu 2n +1 , atau dalam kasus saya 2003. Estimasi ini berubah sesuai jika saya berubah TOP n. Tentu saja, karena ini adalah nested join, jumlah aktual eksekusi adalah 16rb (jumlah baris dari tabel A) dan ini memperlambat query.

Skenario aktual sedikit lebih rumit tetapi ini menangkap ide dasar / perilaku. Kedua tabel dicari menggunakan indeks pencarian. Ini adalah edisi SQL Server 2008 R2 Enterprise.

David
sumber
Permintaan memiliki ORDER BYklausa. Menambahkan TOPperubahan di mana dalam rencana semacam ini terjadi, tapi saya lebih khawatir tentang bagaimana hal itu mempengaruhi jumlah eksekusi indeks yang dicari terhadap tabel B ... (tentu saja keduanya mungkin terkait - saya tidak tahu)
David
1
Diskusi terkait: FAST num_rowspetunjuk kueri.
Remus Rusanu

Jawaban:

39

Saya akan menduga bahwa ketika sebuah kueri menyertakan TOP dan mesin database akan menjalankan kueri mengabaikan klausa TOP, dan kemudian pada akhirnya hanya mengecilkan hasil yang ditetapkan ke n jumlah baris yang diminta. Rencana eksekusi grafis tampaknya mengindikasikan hal ini - TOP adalah langkah "terakhir". Tetapi tampaknya ada lebih banyak hal yang terjadi.

Cara di atas diungkapkan membuat saya berpikir Anda mungkin memiliki gambaran mental yang salah tentang bagaimana sebuah query dieksekusi. Operator dalam rencana kueri bukan langkah (di mana set hasil lengkap dari langkah sebelumnya dievaluasi oleh yang berikutnya.

SQL Server menggunakan model eksekusi pipelined , di mana setiap operator memperlihatkan metode seperti Init () , GetRow () , dan Close () . Seperti yang ditunjukkan oleh nama GetRow () , operator menghasilkan satu baris pada saat dibutuhkan (seperti yang disyaratkan oleh operator induknya). Ini didokumentasikan dalam referensi Buku Logistik Online dan Operator Fisik , dengan lebih detail di posting blog saya Mengapa Rencana Kueri Jalankan Mundur . Model baris per waktu ini sangat penting dalam membentuk intuisi suara untuk eksekusi permintaan.

Pertanyaan saya adalah, bagaimana (dan mengapa) sebuah TOPklausa berdampak pada rencana eksekusi permintaan?

Beberapa operasi logis seperti TOP, semi gabung dan FAST n petunjuk kueri memengaruhi cara pengoptimal biaya menentukan alternatif rencana eksekusi. Ide dasarnya adalah bahwa satu bentuk rencana yang mungkin dapat mengembalikan n baris pertama lebih cepat daripada rencana lain yang dioptimalkan untuk mengembalikan semua baris.

Misalnya, loop bersarang yang diindeks bergabung seringkali merupakan cara tercepat untuk mengembalikan sejumlah kecil baris, meskipun hash atau gabungan penggabungan dengan pemindaian mungkin lebih efisien pada set yang lebih besar. Cara pengoptimal kueri alasan tentang pilihan-pilihan ini adalah dengan menetapkan Tujuan Baris pada titik tertentu di pohon logis operasi.

Sasaran baris memodifikasi cara alternatif rencana kueri dihitung biayanya. Inti dari itu adalah bahwa pengoptimal dimulai dengan menghitung biaya setiap operator seolah-olah set hasil penuh diperlukan, menetapkan tujuan baris pada titik yang sesuai, dan kemudian bekerja kembali ke pohon rencana memperkirakan jumlah baris yang diharapkan perlu untuk memeriksa untuk memenuhi tujuan baris.

Misalnya, logis TOP(10)menetapkan sasaran baris 10 pada titik tertentu di pohon kueri logis. Biaya operator yang mengarah ke sasaran baris dimodifikasi untuk memperkirakan berapa banyak baris yang harus mereka hasilkan untuk memenuhi sasaran baris. Perhitungan ini bisa menjadi rumit, sehingga lebih mudah untuk memahami semua ini dengan contoh yang berfungsi penuh dan rencana eksekusi beranotasi. Sasaran baris dapat memengaruhi lebih dari pilihan jenis gabungan atau apakah pencarian dan pencarian lebih disukai daripada pemindaian. Lebih detail tentang itu di sini .

Seperti biasa, rencana eksekusi yang dipilih berdasarkan sasaran baris tunduk pada kemampuan penalaran pengoptimal dan kualitas informasi yang diberikan kepadanya. Tidak setiap rencana dengan sasaran baris akan menghasilkan jumlah baris yang diperlukan lebih cepat dalam praktiknya, tetapi menurut model penetapan biaya akan melakukannya.

Jika rencana sasaran baris terbukti tidak lebih cepat, biasanya ada cara untuk mengubah kueri atau memberikan informasi yang lebih baik kepada pengoptimal sehingga rencana yang dipilih secara alami adalah yang terbaik. Pilihan mana yang sesuai dalam kasus Anda tergantung pada rinciannya. Fitur tujuan baris umumnya sangat efektif (meskipun ada bug yang harus diperhatikan ketika digunakan dalam rencana eksekusi paralel).

Permintaan dan rencana khusus Anda mungkin tidak cocok untuk analisis terperinci di sini (dengan segala cara sediakan rencana eksekusi aktual jika Anda mau), tetapi mudah-mudahan gagasan yang diuraikan di sini akan memungkinkan Anda untuk membuat kemajuan ke depan.

Paul White mengatakan GoFundMonica
sumber
12

Ketika Anda menggunakan TOP, Pengoptimal melihat peluang untuk melakukan lebih sedikit pekerjaan. Jika Anda meminta 10 baris, maka ada peluang bagus tidak perlu menghabiskan seluruh rangkaian. Sehingga operator TOP dapat didorong lebih jauh ke kanan. Itu akan terus meminta baris dari operator berikutnya (di sebelah kanan), sampai cukup diterima.

Anda menunjukkan bahwa tanpa TOP, kueri mengurutkan data di bagian paling akhir. Jika mesin dapat mengetahui berapa banyak baris yang akan dipenuhi oleh sambungan terlebih dahulu, mungkin lebih baik menggunakan rencana yang sama, menempatkan posisi TOP di sebelah kiri. Tetapi dengan upaya untuk melakukan Pencocokan Hash menjadi relatif tinggi, dan mungkin tidak ada pilihan untuk Gabung Gabung, Pengoptimal mungkin lebih memilih untuk menyaring TOP lebih jauh ke kanan.

Ketika tabel B ditanya, itu mengambil satu baris sekaligus. Itu sebabnya perkiraannya adalah 1. Ia juga mengasumsikan bahwa hanya akan menemukan baris itu 50% dari waktu. Jadi tebakannya perlu 2n +1 berusaha untuk menemukannya.

Rob Farley
sumber
Tampaknya tidak benar bahwa perkiraan jumlah baris akan berubah berdasarkan cara pengambilan data. Bagaimana cara mendapatkan data seharusnya tidak mempengaruhi kardinalitas. Perubahan dalam cara mengambilnya malah akan tercermin dalam jumlah eksekusi, benar?
David
"Estimasi jumlah baris" adalah per eksekusi. Dalam Nested Loop, sangat mungkin untuk mengeksekusi lebih dari sekali.
Rob Farley
Ini akan menjadi perilaku yang berbeda dari Jumlah Aktual Baris dan jumlah (aktual) eksekusi kemudian. Jika rencana aktual menunjukkan 16.834 eksekusi aktual dan 15.407 baris aktual dikembalikan, saya menganggap ini berarti 16k mencari tetapi hanya menemukan 15k cocok dengan predikat. Jika itu artinya 15k baris per eksekusi, ini akan menjadi 15k * 16k = 240 juta baris - sekitar 10 kali lebih besar dari tabel ...
David
Juga, saya tidak yakin saya mengikuti pernyataan terakhir dari jawaban Anda. Ketika Anda mengatakan 2n +1 berusaha menemukan "itu", apa yang Anda maksud dengan "itu"? Tentunya bukan satu baris? Apakah maksud Anda bahwa pengoptimal mengasumsikan bahwa untuk setiap baris yang diberikan dalam A ada peluang 50% akan dicocokkan dengan B dan oleh karena itu perlu "mencoba" 2003 baris dari A untuk mendapatkan 1001 pertandingan dari B? Apakah perilaku ini didokumentasikan di mana saja oleh Microsoft? Dan apa hubungannya dengan TOPklausa? Terima kasih atas jawaban / kesabaran Anda.
David
Ya, Perkiraan Baris adalah per eksekusi Baris aktual adalah total. Meskipun, tidak ada masalah memiliki operator mengembalikan lebih banyak baris daripada yang ada dalam tabel, karena sangat mudah untuk menunjukkan operator mengembalikan baris yang sama beberapa kali.
Rob Farley