Mengapa SQL Server mengembalikan beberapa baris saat masih menjalankan kueri, dan terkadang tidak?

33

Ada kueri di mana ketika kita menekan "mengeksekusi", ini menunjukkan beberapa baris dan terus bertambah, tetapi kueri belum berakhir. Namun terkadang, menunggu sampai akhir permintaan.

Mengapa ini terjadi? Apakah ada cara untuk mengendalikan ini?

SQL pembalap
sumber

Jawaban:

43

Jawabannya, seperti biasa (baik-baik saja, sebagian besar waktu), terletak pada rencana eksekusi.

Ada operator tertentu yang meminta semua baris untuk sampai pada mereka sebelum mereka dapat mulai memproses baris tersebut, dan meneruskannya ke hilir, misalnya:

  • Hash Join (untuk membuat tabel hash)
  • Pertandingan Hash
  • Sortir (Kecuali Perbedaan Aliran Hash)

Mereka disebut memblokir, atau menghentikan dan pergi karena itu, dan mereka sering dipilih ketika pengoptimal berpikir itu harus memproses banyak data untuk menemukan data Anda.

Ada operator lain yang dapat mulai streaming, atau melewati setiap baris yang ditemukan dengan segera

  • Loop bersarang
  • Indeks mendukung Gabung Bergabung
  • Agregat Aliran

Ketika kueri mulai mengembalikan data dengan segera, tetapi tidak menyelesaikannya dengan segera, biasanya itu merupakan tanda bahwa pengoptimal memilih rencana untuk menemukan dan mengembalikan beberapa baris dengan cepat menggunakan operator yang memiliki biaya awal yang lebih rendah.

Ini dapat terjadi karena sasaran baris yang diperkenalkan oleh Anda, atau oleh pengoptimal.

Ini juga dapat terjadi jika rencana buruk dipilih karena beberapa alasan (kurangnya SARGability, parameter sniffing, statistik tidak mencukupi, dll.), Tetapi itu membutuhkan lebih banyak penggalian untuk mencari tahu.

Untuk informasi lebih lanjut, lihat blog Rob Farley di sini

Dan seri Paul White tentang tujuan baris di sini , di sini , di sini , dan di sini .

Perlu juga dicatat bahwa, jika Anda berbicara tentang SSMS, baris hanya muncul setelah seluruh buffer telah diisi, bukan hanya mau tak mau.

Erik Darling
sumber
14

Jika saya mengerti apa yang Anda amati, ini adalah bagaimana Studio Manajemen membuat baris, dan tidak ada hubungannya dengan bagaimana SQL Server mengembalikan baris. Bahkan sering kali ketika Anda mengembalikan hasil besar ke SSMS dan mencoba merendernya dalam kotak, SSMS tidak dapat mengikuti dan SQL Server akhirnya menunggu aplikasi untuk memproses lebih banyak baris. Dalam hal ini Anda akan melihat SQL Server mengumpulkan ASYNC_NETWORK_IOmenunggu.

Anda dapat mengontrolnya dengan menggunakan Hasil ke Teks daripada Hasil ke Kotak, karena SSMS dapat menggambar teks lebih cepat daripada yang bisa menggambar kotak, tetapi Anda mungkin akan menemukan ini dapat mempengaruhi keterbacaan tergantung pada jumlah kolom dan tipe data yang terlibat. Keduanya dipengaruhi oleh ketika SSMS memutuskan untuk benar-benar menulis hasil ke panel itu, yang tergantung pada seberapa penuh buffer output.

Saat Anda memiliki beberapa pernyataan, dan Anda ingin memaksa buffer untuk memberikan hasil keluaran ke panel pesan, Anda bisa menggunakan sedikit trik pencetakan di antara pernyataan:

RAISERROR('', 0, 1) WITH NOWAIT;

Tapi ini tidak akan membantu ketika Anda mencoba untuk mendapatkan SSMS untuk membuat baris lebih cepat ketika semua output berasal dari satu pernyataan.

Lebih langsung, Anda dapat mengontrolnya dengan membatasi berapa banyak hasil yang Anda render dalam SSMS. Saya sering melihat orang mengeluh tentang berapa lama untuk mengembalikan satu juta baris ke grid. Apa yang akan dilakukan seseorang dengan sejuta baris dalam kisi SSMS, saya tidak tahu.

Ada beberapa retas seperti OPTION (FAST 100), yang akan dioptimalkan untuk mengambil 100 baris pertama (atau 100 baris jika tidak ada bagian luar ORDER BY), tetapi ini bisa terjadi dengan biaya pengambilan yang jauh lebih lambat untuk sisa baris dan rencana yang lebih secara keseluruhan tidak efisien, jadi bukan benar-benar pilihan IMHO.

Aaron Bertrand
sumber
1

Pertanyaan Anda bukan tentang SQLServer, tetapi:

  • SQLServer
  • jaringan
  • SSMS sebagai aplikasi klien

Apakah ada cara untuk mengendalikan ini?

Jawaban singkat :

  1. Coba sqlcmdalih-alih ssmsatau sqlcmd-mode darissms
  2. Periksa pengaturan koneksi dan sesi Anda

Jawaban panjang :

Tentu saja! Tapi tidak satu - prob

  1. Jalankan permintaan Anda dengan sqlcmdatau dalam sqlcmd-mode dalam ssms.
  2. Jika Anda ingin mengecualikan peran jaringan - jalankan kueri Anda di server dengan koneksi Memori Bersama.
  3. Jika kinerja kueri tidak memuaskan bahkan dengan koneksi Memori Bersama - analisis rencana eksekusi Anda. Jika kueri berkinerja buruk melalui jaringan - hubungi administrator jaringan Anda untuk meminta bantuan. Jika kueri Anda hanya berkinerja buruk di SSMS - baca lebih lanjut.
  4. Sekarang kami yakin bahwa masalahnya ada di sisi klien (ssms dalam kasus ini). Lihatlah pengaturan koneksi dan sesi di SSMS. Jangan percaya antarmuka ssms dan periksa dengan SQL Profiler: cari koneksi spidAnda dan Anda mendapatkan daftar pengaturan sesi lengkap. Bandingkan dengan pengaturan sqlcmdsesi. Jika tidak ada yang diklik - salin semua pengaturan sesi dari profiler ke skrip kueri Anda, jalankan di sqlcmd-mode dan secara bertahap beralih pengaturan Anda akan menemukan pelakunya.

Semoga berhasil!

Alex Yu
sumber
-2

Untuk menambahkan jawaban sp_BlitzErik, ambil contoh menggunakan NOT IN ()sub dengan pilih. Untuk menentukan apakah suatu item dalam hasil query bersarang, itu (umumnya) perlu untuk mengambil seluruh hasil.

Jadi salah satu cara mudah yang saya temukan untuk meningkatkan kinerja permintaan seperti itu adalah menulis ulang mereka sebagai LEFT OUTER JOINdengan kondisi di mana RIGHTsisi adalah nol (Anda dapat membalikkannya, tentu saja tetapi siapa yang menggunakan RIGHT OUTER JOINS?). Ini memungkinkan hasil mulai kembali segera.

JimmyJames
sumber
Saya kira tidak. Jika kolom yang dibandingkan tidak nullable, maka hasilnya harus sama dan rencana - biasanya - sama, untuk 3 versi antijoin (BUKAN DALAM, BUKAN ADA, GABUNGAN KIRI / IS NULL). Tidak perlu mengambil seluruh hasil.
ypercubeᵀᴹ
Jika subselect adalah benar-benar kompleks yang kueri yang dihasilkan perlu mengevaluasi seluruh subselect sebelum memeriksa kondisi NOT IN,, WHERE t.x IN (<complex SELECT subquery>)KIRI LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULLKIRIM yang setara ,, maka subquery juga akan dievaluasi, juga (jadi rencana kompleks yang sama dengan NOT Dalam versi).
ypercubeᵀᴹ
@ ypercubeᵀᴹ Dulu berhasil untuk saya. Saya telah melihat pertanyaan mulai dari mengambil menit hingga kembali ke subsecond.
JimmyJames
@ ypercubeᵀᴹ Saya membuat contoh sederhana di Oracle (maaf saya tidak memiliki akses ke SQLServer saat ini) dan mereka pasti punya rencana menjelaskan yang berbeda. Mungkin mereka bukan perbedaan yang berarti tetapi mereka terlihat sangat berbeda.
JimmyJames
@ JimmyJames: ini bukan cara sederhana jika Anda ingin kinerja yang stabil dan "optimasi" seperti itu sangat sensitif untuk versi SQLServer. Dan jangan membuat kesalahan yang menarik bagi Oracle (versi yang mana?). Secara historis SQLServer lebih disukai NOT EXISTStetapi Oracle NOT INdalam kueri. Tapi hari ini itu harus dianggap sebagai kesalahan dalam generator rencana
Alex Yu