SQL Server Linked Server kinerja: Mengapa permintaan jarak jauh begitu mahal?

14

Saya memiliki dua server basis data, terhubung melalui Server Tertaut. Keduanya adalah database SQL Server 2008R2, dan koneksi server tertaut dibuat melalui tautan "SQL Server" biasa, menggunakan konteks keamanan login saat ini. Server yang ditautkan keduanya berada di pusat data yang sama, sehingga koneksi tidak menjadi masalah.

Saya menggunakan kueri berikut untuk memeriksa nilai kolom mana identifieryang tersedia dari jarak jauh, tetapi tidak secara lokal.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

Di kedua tabel adalah indeks non-cluster di kolom identifier. Secara lokal sekitar 2,6 juta baris, hanya berjarak 54. Namun, ketika melihat rencana kueri, 70% dari waktu eksekusi dikhususkan untuk "mengeksekusi kueri jarak jauh". Juga, ketika mempelajari rencana kueri yang lengkap, jumlah baris lokal yang diestimasi 1bukan 2695380(yang merupakan jumlah baris yang diestimasikan ketika memilih hanya query yang datang setelahnya EXCEPT). Rencana eksekusi Saat menjalankan kueri ini, memang butuh waktu lama.

Itu membuat saya bertanya-tanya: Mengapa ini? Apakah perkiraan "hanya" jauh, atau apakah pertanyaan jarak jauh pada server yang terhubung benar-benar mahal?

vstrien
sumber
2
BTW: Ini adalah "estimasi jumlah eksekusi" yang harus Anda cari untuk pencarian indeks. Perkiraan jumlah baris adalah baris output per eksekusi yang tidak akan terkait dengan jumlah baris dalam tabel itu sendiri kecuali paket tersebut memiliki pemindaian penuh.
Martin Smith

Jawaban:

9

Rencana yang Anda miliki saat ini terlihat seperti rencana paling optimal bagi saya.

Saya tidak setuju dengan pernyataan di jawaban lain bahwa ia mengirim baris 2.6M ke server jarak jauh.

Rencana itu terlihat bagi saya seolah-olah untuk masing-masing 54 baris yang dikembalikan dari permintaan jarak jauh itu melakukan pencarian indeks ke tabel lokal Anda untuk menentukan apakah cocok atau tidak. Ini adalah rencana optimal.

Mengganti dengan hash bergabung atau menggabungkan bergabung akan menjadi kontraproduktif mengingat ukuran tabel dan menambahkan #temptabel perantara hanya menambahkan langkah tambahan yang tampaknya tidak memberi Anda keuntungan apa pun.

Martin Smith
sumber
6

Menghubungkan ke sumber daya jarak jauh mahal. Titik.

Salah satu operasi yang paling mahal di lingkungan pemrograman apa pun adalah IO jaringan (meskipun disk IO cenderung mengecilkannya).

Ini meluas ke server yang terhubung jauh. Server yang memanggil server yang terhubung jauh perlu terlebih dahulu membuat koneksi, kemudian permintaan harus dijalankan pada server jauh, hasilnya dikembalikan dan koneksi ditutup. Ini semua membutuhkan waktu melalui jaringan.


Anda juga harus menyusun kueri Anda sedemikian rupa sehingga Anda mentransfer data minimum melalui kawat. Jangan berharap DB akan mengoptimalkan untuk Anda.

Jika saya menulis kueri ini, saya akan memilih data jarak jauh menjadi variabel tabel (atau ke tabel temp) dan kemudian menggunakan ini dalam hubungannya dengan tabel lokal. Ini memastikan bahwa hanya data yang perlu ditransfer yang akan.

Kueri yang Anda jalankan dapat dengan mudah mengirim baris 2,6M ke server jarak jauh untuk memproses EXCEPTklausa.

Oded
sumber
Oke, jadi ada biaya awal yang tinggi untuk mengatur koneksi. Permintaan perlu dikirim, diproses dari jarak jauh (tidak diperlukan jaringan untuk yang itu), dan akhirnya hasilnya dikirim kembali dan diproses. Tapi itu tidak akan memakan waktu beberapa menit untuk mengirim data melalui koneksi jaringan, bukan?
vstrien
@vstrien - Mungkin. Tergantung pada koneksi jaringan, latensi, saturasi dan faktor lainnya. Gunanya - itu tidak deterministik.
@vstrien - Menambahkan lebih banyak informasi dalam jawaban saya. Saya percaya permintaan seperti yang tertulis akan mengirim baris lokal ke server jauh untuk diproses.
2
Di mana Anda menyimpulkan fakta bahwa ia mengirim baris 2,6M ke server jarak jauh? Saya tidak punya banyak pengalaman dengan rencana dengan operator kueri jarak jauh tetapi tampaknya seolah-olah 54 baris keluar dari operator kueri jarak jauh maka ia melakukan anti semi join terhadap tabel lokal.
Martin Smith
2
@ Lieven - Mungkin logis tetapi tidak berpikir itu benar dari rencana yang ditampilkan.
Martin Smith
1

Saya bukan ahli tetapi jika Anda menggunakan Union, Kecuali, atau Intersect, Anda tidak harus menggunakan "Distinct". Bergantung pada nilai-nilai dari LocalDb.schema. [TableName], kinerja kueri dapat ditingkatkan.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]
joakon
sumber
0

Oded benar, masalah kinerja disebabkan oleh pengiriman baris 2.6M ke server jarak jauh Anda.

Untuk memperbaiki masalah ini, Anda dapat memaksa data jarak jauh (54 baris) dikirim kepada Anda dengan menggunakan temp atau di tabel memori.

Menggunakan tabel sementara

SELECT  identifier 
INTO    #TableName
FROM    LinkedServer.RemoteDb.schema.[TableName]

SELECT  identifier
FROM    #TableName
EXCEPT
SELECT  DISTINCT identifier 
FROM    LocalDb.schema.[TableName] 

DROP    #TableName
Letnan Keersmaekers
sumber
Menggunakan tabel sementara dapat membantu dengan perkiraan kardinalitas dalam peristiwa apa pun meskipun loop bersarang tampaknya masuk akal untuk hanya 54 baris.
Martin Smith
Menggunakan tabel sementara berfungsi dengan 54 baris; tetapi dalam kasus dengan meja besar di kedua sisi itu tidak layak lagi. Apa solusi Anda untuk dua tabel "besar" berukuran sama? Membuat UserTable, di database lain?
vstrien
1
@vstrien - sebenarnya tidak ada solusi yang baik untuk dua tabel besar berukuran sama. Mungkin membuat Tampilan Partisi Terdistribusi menarik bagi Anda, tetapi saya tidak punya pengalaman apa pun dengannya.
Lieven Keersmaekers
0

Saya pikir Anda lebih baik mereplikasi tabel jarak jauh ke server tempat Anda bertanya dan kemudian menjalankan semua SQL Anda secara lokal.

Alen
sumber