Masalah kinerja SQL dengan kueri jarak jauh di server yang ditautkan

8

Sproc ini

create proc dbo.Get_Accounts as
begin
  declare @current_date datetime
  set @current_date = dbo.fn_currdate()

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = @current_date
end

terus gagal setelah 10 menit dengan pesan kesalahan berikut:

Server: Msg 7399, Level 16, Negara 1, Jalur 1 Penyedia DB OLE 'SQLOLEDB' melaporkan kesalahan. Eksekusi dihentikan oleh penyedia karena batas sumber daya tercapai. [OLE / penyedia DB mengembalikan pesan: Batas waktu kedaluwarsa] OLE DB trace trace [OLE / DB Provider 'SQLOLEDB' ICommandText :: Jalankan kembali 0x80040e31: Eksekusi diakhiri oleh penyedia karena batas sumber daya tercapai.].

Namun, ketika saya menjalankan kueri yang sama dari database yang sama (bukan pada yang jauh) di jendela kueri interaktif dengan tanggal hard-coded:

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = '1/20/2012'

Ia kembali dalam 30 detik.

Server lokal adalah SQLSERVER 2008, remote adalah SQLSERVER 2000.

Kami telah melakukan yang berikut ini tanpa hasil:

  • Membuat proc yang disimpan.
  • sp_recompile pada proc yang disimpan
  • perbarui statistik di dbo.accounts
  • menjatuhkan dan membuat ulang indeks di dbo.accounts
  • menjatuhkan indeks pada dbo.accounts dan coba
  • DBCC FREEPROCCACHE & DBCC DROPCLEANBUFFERS di server lokal dan jauh
  • Reboot server jarak jauh (bukan opsi yang mudah pada server lokal)

Pertanyaan

  • Adakah yang bisa menjelaskan perilaku aneh ini?
  • Adakah saran tentang opsi lain untuk memperbaikinya?
Bob Probst
sumber

Jawaban:

11

Anda dapat mengaktifkan jejak bendera 7300 yang mungkin memberi Anda pesan kesalahan yang lebih rinci

Berapa banyak baris yang dikembalikan kueri representatif? Seberapa cepat / dapat diandalkan koneksi jaringan antara dua server?

Ada kemungkinan bahwa dataset besar terlalu lama untuk ditransfer (di atas waktu kueri yang sebenarnya). Anda dapat menaikkan nilai batas waktu.

Anda dapat mencoba mengkonfigurasi ulang pengaturan batas waktu sebagai berikut:

Atur batas waktu login jarak jauh menjadi 300 detik:

sp_configure 'remote login timeout', 300
go 
reconfigure with override 
go 

Setel batas waktu kueri jarak jauh ke 0 (menunggu tak terbatas):

sp_configure 'remote query timeout', 0 
go 
reconfigure with override 
go 

Pembaruan : SQL Server 2012 SP1 dan seterusnya : pengguna dengan SELECTizin akan dapat mengakses DBCC SHOW_STATISTICSyang akan meningkatkan kinerja hanya baca di server yang ditautkan. Ref: https://msdn.microsoft.com/en-us/library/ms174384(v=sql.110).aspx

Pembaruan : Anda benar dalam mengatakan itu bukan ukuran data atau kecepatan koneksi. Itu membunyikan lonceng dalam ingatanku yang berkabut dan aku ingat di mana aku melihatnya: Lambat dalam Aplikasi, Cepat dalam SSMS? (Masalah dengan Server Tertaut). Ini bukan parameter sniffing, statistik itu sendiri yang hilang (karena izin), menyebabkan rencana kueri yang buruk untuk digunakan:

Anda dapat melihat bahwa perkiraannya berbeda. Ketika saya berlari sebagai sysadmin, perkiraannya adalah 1 baris, yang merupakan angka yang benar, karena tidak ada Pesanan di Northwind di mana ID pesanan melebihi 20000. Tetapi ketika saya berlari sebagai pengguna biasa, perkiraannya adalah 249 baris. Kami mengenali nomor khusus ini sebagai 30% dari 830 pesanan, atau perkiraan untuk operasi ketimpangan ketika pengoptimal tidak memiliki informasi. Sebelumnya, ini disebabkan oleh nilai variabel yang tidak diketahui, tetapi dalam kasus ini tidak ada variabel yang tidak bisa diketahui. Tidak, statistiknya sendiri yang hilang.

Selama kueri hanya mengakses tabel di server lokal, pengoptimal selalu dapat mengakses statistik untuk semua tabel dalam kueri; tidak ada pemeriksaan izin tambahan. Tapi ini berbeda dengan tabel di server yang ditautkan. Ketika SQL Server mengakses server tertaut, tidak ada protokol rahasia yang hanya digunakan untuk komunikasi antar-server. Tidak, alih-alih SQL Server menggunakan antarmuka OLE DB standar untuk server yang ditautkan, menjadi instance SQL Server lainnya, Oracle, file teks atau sumber data buatan sendiri, dan menghubungkan sama seperti pengguna lain. Bagaimana tepatnya statistik diambil tergantung pada sumber data dan penyedia OLE DB yang bersangkutan. Dalam hal ini, penyedianya adalah SQL Server Native Client yang mengambil statistik dalam dua langkah. (Anda dapat melihat ini dengan menjalankan Profiler terhadap server jauh). Pertama penyedia menjalankan prosedur sp_table_statistics2_rowset yang mengembalikan informasi tentang statistik kolom mana yang ada, serta kardinalitas dan informasi kepadatannya. Pada langkah kedua, penyedia menjalankan DBCC SHOW_STATISTICS, sebuah perintah yang mengembalikan statistik distribusi lengkap. (Kita akan melihat lebih dekat pada perintah ini nanti dalam artikel ini.) Ini adalah tangkapannya: untuk menjalankan DBCC SHOW_STATISTICS, Anda harus menjadi anggota sysadmin peran server atau salah satu dari peran basis data db_owner atau db_ddladmin.

Dan inilah mengapa saya mendapat hasil yang berbeda. Ketika berjalan sebagai sysadmin saya mendapatkan statistik distribusi lengkap yang menunjukkan bahwa tidak ada baris dengan ID pesanan> 20000, dan perkiraannya adalah satu baris. (Ingat bahwa pengoptimal tidak pernah mengasumsikan nol baris dari statistik.) Tetapi ketika berjalan sebagai pengguna biasa, DBCC SHOW_STATISTICS gagal dengan kesalahan izin. Kesalahan ini tidak disebarkan, tetapi pengoptimal menerima bahwa tidak ada statistik dan menggunakan asumsi default. Karena ia mendapatkan informasi kardinalitas, ia mengetahui bahwa tabel jarak jauh memiliki 830 baris, di mana perkiraan 249 baris.

Setiap kali Anda menghadapi masalah kinerja di mana kueri yang menyertakan akses ke server terkait lambat dalam aplikasi, tetapi itu berjalan cepat saat Anda mengujinya dari SSMS, Anda harus selalu menyelidiki apakah izin yang tidak memadai pada basis data jauh dapat menjadi penyebabnya. (Ingatlah bahwa akses ke server yang ditautkan mungkin tidak terbuka dalam kueri, tetapi dapat disembunyikan dalam tampilan.) Jika Anda menentukan bahwa izin pada basis data jauh adalah masalahnya, tindakan apa yang bisa Anda ambil?

  • Anda dapat menambahkan pengguna ke peran db_ddladmin, tetapi karena ini memberi mereka hak untuk menambah dan menjatuhkan tabel, ini tidak dianjurkan.

  • Secara default, ketika pengguna terhubung ke server jauh mereka terhubung sebagai diri mereka sendiri, tetapi Anda dapat mengatur pemetaan login dengan sp_addlinkedsrvlogin, sehingga pengguna memetakan ke akun proxy yang memiliki keanggotaan di db_ddladmin. Perhatikan bahwa akun proksi ini harus berupa login SQL, jadi ini bukan opsi jika server jarak jauh tidak mengaktifkan otentikasi SQL. Solusi ini juga agak meragukan dari sudut pandang keamanan, meskipun lebih baik saran sebelumnya.

  • Dalam beberapa kasus, Anda dapat menulis ulang kueri dengan OPENQUERY untuk memaksa evaluasi pada server jarak jauh. Ini bisa sangat berguna, jika kueri menyertakan beberapa tabel jarak jauh. (Tapi itu juga bisa menjadi bumerang, karena pengoptimal sekarang mendapatkan informasi statistik lebih sedikit dari server jauh.)

  • Anda tentu saja dapat menggunakan baterai penuh petunjuk dan panduan rencana untuk mendapatkan rencana yang Anda inginkan.

  • Akhirnya, Anda harus bertanya pada diri sendiri apakah akses server terkait itu diperlukan. Mungkin database bisa berada di server yang sama? Bisakah data direplikasi? Beberapa solusi lain?

Mitch Wheat
sumber
Ini mengembalikan sekitar 140 ribu catatan. tetapi karena itu berfungsi dengan baik ketika nilai tanggal hardcoded saya tidak bisa memikirkan I / O atau masalah jaringan yang akan sangat mempengaruhi versi parameterisasi. Naluriku mengatakan bahwa kueri sedang diteruskan ke server jauh dan pengoptimal jarak jauh entah bagaimana memilih rencana kueri yang buruk ketika tidak dapat memahami parameter. Tetapi pengindeksan ulang dan pembersihan cache / buffer harus memperbaiki itu (saya berasumsi). Saya akan melihat timeout untuk melihat apakah kita bisa membuatnya setidaknya kembali. Terima kasih
1
Jawaban yang sangat bagus dan menjelaskan dengan tepat masalah yang saya alami, terima kasih. Saya akan menambahkan bahwa menurut MSDN , dari SQL2012 SP1 dan seterusnya, pengguna dengan SELECTizin akan dapat mengakses DBCC SHOW_STATISTICSyang akan meningkatkan kinerja hanya baca di server yang ditautkan tanpa harus membahayakan keamanan.
Steve Pettifer
2

Apa yang terjadi ketika Anda mencoba ini (yaitu secara eksplisit menunjukkan apa yang harus dijalankan pada server jauh) ?:

select [fields]
into dbo.current_accounts
from OPENQUERY(linkedserver, 'SELECT [fields] FROM database.dbo.accounts where date = ''1/20/2012''');

Saya menduga dalam kasus Anda di atas SQL Server hanya menarik seluruh tabel dari server jauh kemudian menjalankan kueri secara lokal (saya telah melihat ini terjadi berkali-kali di masa lalu). Saya lebih suka eksplisit (baik dengan menggunakan OPENQUERY atau dengan membuat SP di server jauh) sehingga tidak ada kemungkinan kebingungan.

Gareth
sumber
1

Karena ini adalah masalah sumber daya ulang, kumpulan memori di luar SQL server yang digunakan untuk memuat driver eksternal dan CLR mungkin mendekati batasnya. Standarnya adalah 256MB. Untuk menyiasatinya, saya sarankan Anda pergi ke manajer konfigurasi server SQL, tab tingkat lanjut dan tambahkan opsi -g ke bagian akhir parameter startup.ie; -g1024 kemudian restart layanan SQL Server. Saya biasanya melakukan ini karena kami menggunakan banyak server yang terhubung. http://msdn.microsoft.com/en-us/library/ms190737.aspx

nopol
sumber
1

Saya punya dua ide yang mungkin bisa membantu. Saya juga akan memberi tahu Anda bahwa saya mengalami nasib buruk dengan kinerja menjalankan kueri terhadap server yang ditautkan. Jadi rekomendasi pertama saya adalah untuk menghindarinya jika Anda bisa.

Ide pertama saya adalah menginstal prosedur yang tersimpan ke dalam kotak SQL Server 2000, setelah itu referensi server lokal. Anda kemudian dapat menjalankan prosedur tersimpan dari jarak jauh.

exec linkedserver.database.dbo.Get_Accounts

Jika Anda dapat menempuh rute ini, itu akan meningkatkan kinerja luar biasa.

Gagasan kedua saya adalah mendapatkan perkiraan rencana kueri saat menjalankan prosedur tersimpan. Apakah ini menunjukkan kepada Anda apa yang menghabiskan begitu banyak waktu? Salah satu masalah potensial adalah bahwa akun yang Anda gunakan di server yang ditautkan mungkin tidak memiliki cukup otoritas untuk mendapatkan statistik tabel (Anda memerlukan lebih banyak otoritas untuk server yang ditautkan daripada yang Anda lakukan untuk server lokal). Dan itu bisa membuat pertanyaan sangat lambat. Anda dapat membaca lebih lanjut tentang masalah khusus itu di sini .

Jeff Siver
sumber