Wydajność połączonego serwera SQL Server: Dlaczego zdalne zapytania są tak drogie?

14

Mam dwa serwery bazy danych, połączone przez połączone serwery. Obie są bazami danych SQL Server 2008R2, a połączone połączenie z serwerem jest nawiązywane za pomocą zwykłego łącza „SQL Server”, z wykorzystaniem kontekstu bezpieczeństwa bieżącego logowania. Połączone serwery znajdują się w tym samym centrum danych, więc połączenie nie powinno stanowić problemu.

Korzystam z następującego zapytania, aby sprawdzić, które wartości kolumny identifiersą dostępne zdalnie, ale nie lokalnie.

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

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

W obu tabelach znajdują się indeksy nieklastrowane w kolumnie identifier. Lokalnie jest około 2,6 miliona wierszy, zdalnie tylko 54. Jednak patrząc na plan zapytań, 70% czasu wykonania jest poświęcone na „wykonanie zapytania zdalnego”. Ponadto podczas badania pełnego planu zapytań 1zamiast szacowanych wierszy lokalnych 2695380(jest to liczba szacowanych wierszy przy wyborze tylko zapytania następnego EXCEPT). Plan wykonania Podczas wykonywania tego zapytania rzeczywiście zajmuje to dużo czasu.

Zastanawiam się: dlaczego? Czy oszacowanie jest „po prostu” daleko, czy zdalne zapytania na połączonych serwerach są naprawdę tak drogie?

vstrien
źródło
2
BTW: Jest to „szacunkowa liczba egzekucji”, na którą powinieneś szukać wyszukiwania indeksu. Szacowana liczba wierszy to wynik wierszy na wykonanie, który nie będzie związany z liczbą wierszy w samej tabeli, chyba że plan ma pełne skanowanie.
Martin Smith

Odpowiedzi:

9

Plan, który masz w tej chwili, wydaje mi się najbardziej optymalnym planem.

Nie zgadzam się z twierdzeniem zawartym w innych odpowiedziach, że wysyła on 2,6 mln wierszy do zdalnego serwera.

Plan wydaje mi się, że dla każdego z 54 wierszy zwróconych ze zdalnego zapytania wykonuje wyszukiwanie indeksu do lokalnej tabeli w celu ustalenia, czy jest on zgodny. To właściwie optymalny plan.

Zastąpienie łączeniem mieszającym lub łączeniem scalającym przyniosłoby efekt przeciwny do zamierzonego, biorąc pod uwagę rozmiar tabeli, a dodanie #temptabeli pośredniej stanowi tylko dodatkowy krok, który wydaje się nie dać żadnej korzyści.

Martin Smith
źródło
6

Połączenie ze zdalnym zasobem jest drogie. Kropka.

Jedną z najdroższych operacji w każdym środowisku programistycznym jest sieciowe we / wy (choć dyskowe we / wy mają tendencję do zmniejszania go).

Dotyczy to również zdalnie połączonych serwerów. Serwer wywołujący zdalnie połączony serwer musi najpierw ustanowić połączenie, a następnie wykonać zapytanie na serwerze zdalnym, wyniki zostaną zwrócone, a połączenie zamknięte. Wszystko to wymaga czasu w sieci.


Powinieneś także ułożyć strukturę zapytania w taki sposób, aby przesyłać minimalne dane przez drut. Nie oczekuj, że DB zoptymalizuje się dla Ciebie.

Gdybym miał napisać to zapytanie, wybrałbym dane zdalne do zmiennej tabeli (lub tabeli tymczasowej), a następnie używałbym tego w połączeniu z tabelą lokalną. Zapewnia to, że przesyłane będą tylko dane, które należy przesłać.

Zapytanie, które uruchamiasz, może łatwo wysyłać 2,6 mln wierszy do zdalnego serwera w celu przetworzenia EXCEPTklauzuli.

Oded
źródło
Ok, więc skonfigurowanie połączenia ma wysokie koszty uruchomienia. Zapytanie należy wysłać, przetworzyć zdalnie (nie wymaga sieci), a na koniec wyniki odesłać i przetworzyć. Ale wysłanie danych przez połączenie sieciowe nie zajmie minut, prawda?
vstrien
@vstrien - Może. Zależy od połączenia sieciowego, opóźnienia, nasycenia i innych czynników. Byt punktowy - nie jest deterministyczny.
@vstrien - Dodano więcej informacji w mojej odpowiedzi. Wierzę, że zapytanie w formie pisemnej wyśle ​​lokalne wiersze do zdalnego serwera w celu przetworzenia.
2
Skąd wnioskujesz, że wysyła on 2,6 mln wierszy do zdalnego serwera? Nie mam dużego doświadczenia z planami ze zdalnymi operatorami zapytań, ale wygląda na to, że 54 wiersze wychodzą ze zdalnego operatora zapytań, a następnie wykonuje anty-semi-złączenie z tabelą lokalną.
Martin Smith
2
@Lieven - Może być logiczne, ale nie sądzę, że jest to zgodne z przedstawionym planem.
Martin Smith
1

Nie jestem ekspertem, ale jeśli używasz Union, z wyjątkiem lub Intersect, nie musisz używać „Distinct”. W zależności od wartości z LocalDb.schema. [TableName] można zwiększyć wydajność zapytania.

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

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]
joakon
źródło
0

Oded ma rację, problem z wydajnością jest spowodowany wysyłaniem 2,6 mln wierszy na zdalny serwer.

Aby rozwiązać ten problem, możesz wymusić wysyłanie zdalnych danych (54 wierszy) za pomocą tabeli tymczasowej lub w pamięci.

Korzystanie ze stołu tymczasowego

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

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

DROP    #TableName
Lieven Keersmaekers
źródło
Użycie tabeli tymczasowej może pomóc w oszacowaniu liczności w każdym przypadku, chociaż zagnieżdżone pętle wydają się rozsądne tylko dla 54 wierszy.
Martin Smith
Korzystanie z tabeli tymczasowej działa poprawnie z 54 wierszami; ale w przypadkach z dużymi stolikami po obu stronach nie jest to już możliwe. Jakie byłoby Twoje rozwiązanie dla dwóch jednakowych rozmiarów „dużych” stołów? Tworzenie tabeli użytkowników w innej bazie danych?
vstrien
1
@vstrien - nie ma naprawdę dobrego rozwiązania dla dwóch ogromnych stołów o równej wielkości. Być może utworzenie rozproszonego widoku podzielonego na partycje jest dla Ciebie interesujące, ale nie mam z tym żadnego doświadczenia.
Lieven Keersmaekers
0

Myślę, że lepiej powielić zdalną tabelę na serwerze, z którego następuje zapytanie, a następnie uruchomić lokalnie cały SQL.

Alen
źródło