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 identifier
są 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ń 1
zamiast szacowanych wierszy lokalnych 2695380
(jest to liczba szacowanych wierszy przy wyborze tylko zapytania następnego EXCEPT
).
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?
Odpowiedzi:
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
#temp
tabeli pośredniej stanowi tylko dodatkowy krok, który wydaje się nie dać żadnej korzyści.źródło
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
EXCEPT
klauzuli.źródło
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.
źródło
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
źródło
Myślę, że lepiej powielić zdalną tabelę na serwerze, z którego następuje zapytanie, a następnie uruchomić lokalnie cały SQL.
źródło