У меня есть два сервера баз данных, подключенных через связанные серверы. Обе они являются базами данных 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.6M на удаленный сервер.
План выглядит для меня так, как будто для каждой из 54 строк, возвращенных из удаленного запроса, выполняется поиск по индексу в вашей локальной таблице, чтобы определить, соответствует ли он или нет. Это в значительной степени оптимальный план.
Замена хеш-соединением или объединением слиянием будет контрпродуктивной, учитывая размер таблицы, а добавление промежуточной
#temp
таблицы просто добавляет дополнительный шаг, который, кажется, не дает вам никакого преимущества.источник
Подключение к удаленному ресурсу стоит дорого. Период.
Одна из самых дорогих операций в любой среде программирования - сетевой ввод-вывод (хотя дисковый ввод-вывод имеет тенденцию затмевать его).
Это распространяется на удаленные связанные серверы. Сервер, вызывающий удаленный связанный сервер, должен сначала установить соединение, затем на удаленном сервере должен быть выполнен запрос, возвращены результаты и соединение закрыто. Все это требует времени по сети.
Вы также должны структурировать свой запрос таким образом, чтобы передавать минимальные данные по сети. Не ожидайте, что БД оптимизируется для вас.
Если бы я написал этот запрос, я бы выбрал удаленные данные в табличную переменную (или во временную таблицу), а затем использовал бы их в сочетании с локальной таблицей. Это гарантирует, что будут передаваться только те данные, которые необходимо передать.
Запущенный вами запрос может легко отправить 2,6 млн строк на удаленный сервер для обработки
EXCEPT
предложения.источник
Я не эксперт, но если вы используете Union, Except или Intersect, вам не нужно использовать «Distinct». В зависимости от значений из LocalDb.schema. [TableName], производительность запроса может быть улучшена.
источник
Одед прав, проблема с производительностью вызвана отправкой строк 2.6M на удаленный сервер.
Чтобы устранить эту проблему, вы можете принудительно отправить удаленные данные (54 строки), используя временную таблицу или таблицу в памяти.
Использование временной таблицы
источник
Я думаю, что вам лучше реплицировать удаленную таблицу на сервер, с которого вы запрашиваете, а затем запускать весь ваш SQL локально.
источник