Производительность связанного сервера SQL Server: почему удаленные запросы так дороги?


14

У меня есть два сервера баз данных, подключенных через связанные серверы. Обе они являются базами данных SQL Server 2008R2, и связанное соединение с сервером осуществляется через обычную ссылку «SQL Server» с использованием контекста безопасности текущего имени входа. Связанные серверы находятся в одном центре данных, поэтому проблема с подключением не должна быть.

Я использую следующий запрос, чтобы проверить, какие значения столбца identifierдоступны удаленно, но не локально.

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

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

На обеих таблицах есть некластеризованные индексы по столбцу identifier. Локально около 2,6 млн строк, удаленно только 54. Тем не менее, при рассмотрении плана запроса, 70% времени выполнения отводится «выполнению удаленного запроса». Кроме того, при изучении полного плана запроса 1вместо предполагаемого количества локальных строк 2695380(которое является числом предполагаемых строк при выборе только следующего запроса EXCEPT). План выполнения При выполнении этого запроса, это действительно занимает много времени.

Это заставляет меня задуматься: почему это? Оценка "просто" далека или действительно удаленные запросы на связанных серверах настолько дороги?


2
Кстати: это «предполагаемое количество казней», на которые вы должны обратить внимание при поиске индекса. Предполагаемое количество строк - это количество строк, выводимых за выполнение, которое не будет связано с количеством строк в самой таблице, если план не имеет полного сканирования.
Мартин Смит

Ответы:


9

План, который у вас есть на данный момент, выглядит для меня как самый оптимальный.

Я не согласен с утверждением в других ответах о том, что он отправляет строки 2.6M на удаленный сервер.

План выглядит для меня так, как будто для каждой из 54 строк, возвращенных из удаленного запроса, выполняется поиск по индексу в вашей локальной таблице, чтобы определить, соответствует ли он или нет. Это в значительной степени оптимальный план.

Замена хеш-соединением или объединением слиянием будет контрпродуктивной, учитывая размер таблицы, а добавление промежуточной #tempтаблицы просто добавляет дополнительный шаг, который, кажется, не дает вам никакого преимущества.


6

Подключение к удаленному ресурсу стоит дорого. Период.

Одна из самых дорогих операций в любой среде программирования - сетевой ввод-вывод (хотя дисковый ввод-вывод имеет тенденцию затмевать его).

Это распространяется на удаленные связанные серверы. Сервер, вызывающий удаленный связанный сервер, должен сначала установить соединение, затем на удаленном сервере должен быть выполнен запрос, возвращены результаты и соединение закрыто. Все это требует времени по сети.


Вы также должны структурировать свой запрос таким образом, чтобы передавать минимальные данные по сети. Не ожидайте, что БД оптимизируется для вас.

Если бы я написал этот запрос, я бы выбрал удаленные данные в табличную переменную (или во временную таблицу), а затем использовал бы их в сочетании с локальной таблицей. Это гарантирует, что будут передаваться только те данные, которые необходимо передать.

Запущенный вами запрос может легко отправить 2,6 млн строк на удаленный сервер для обработки EXCEPTпредложения.


Итак, для установки соединения требуются высокие затраты на запуск. Запрос должен быть отправлен, обработан удаленно (для этого не требуется сеть) и, наконец, результаты отправлены обратно и обработаны. Но это не займет минут, чтобы отправить данные по сетевому соединению, не так ли?
Встриен

@vstrien - Возможно. Зависит от сетевого подключения, задержки, насыщенности и других факторов. Точка бытия - это не детерминированность.

@vstrien - Добавил больше информации в мой ответ. Я полагаю, что запрос, как написано, отправит локальные строки на удаленный сервер для обработки.

2
Откуда вы выводите тот факт, что он отправляет строки 2.6M на удаленный сервер? У меня нет большого опыта работы с планами с операторами удаленных запросов, но похоже, что 54 строки выходят из оператора удаленных запросов, тогда он выполняет анти-полусоединение с локальной таблицей.
Мартин Смит

2
@Lieven - Может быть, логично, но не думаю, что это правильно из показанного плана.
Мартин Смит

1

Я не эксперт, но если вы используете Union, Except или Intersect, вам не нужно использовать «Distinct». В зависимости от значений из LocalDb.schema. [TableName], производительность запроса может быть улучшена.

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

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]

0

Одед прав, проблема с производительностью вызвана отправкой строк 2.6M на удаленный сервер.

Чтобы устранить эту проблему, вы можете принудительно отправить удаленные данные (54 строки), используя временную таблицу или таблицу в памяти.

Использование временной таблицы

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

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

DROP    #TableName

Использование временной таблицы может помочь с оценками мощности в любом случае, хотя вложенные циклы кажутся разумными только для 54 строк.
Мартин Смит

Использование временной таблицы работает правильно с 54 строками; но в случаях с большими столами с обеих сторон это уже невозможно. Каким будет ваше решение для двух «огромных» столов одинакового размера? Создание пользовательской таблицы в другой базе данных?
Встриен

1
@vstrien - нет действительно хорошего решения для двух огромных таблиц одинакового размера. Возможно, создание распределенного разделенного представления представляет интерес для вас, но у меня нет никакого опыта с ним.
Ливен Керсмакерс

0

Я думаю, что вам лучше реплицировать удаленную таблицу на сервер, с которого вы запрашиваете, а затем запускать весь ваш SQL локально.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.