Проблемы производительности SQL с удаленным запросом через связанный сервер

8

Это sproc

create proc dbo.Get_Accounts as
begin
  declare @current_date datetime
  set @current_date = dbo.fn_currdate()

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = @current_date
end

через 10 минут постоянно происходит сбой со следующим сообщением об ошибке:

Сервер: Msg 7399, уровень 16, состояние 1, строка 1 Поставщик OLE DB «SQLOLEDB» сообщил об ошибке. Исполнение прервано провайдером, поскольку достигнут предел ресурса. [Поставщик OLE / DB возвратил сообщение: Истекло время ожидания] Трассировка ошибки OLE DB [Поставщик OLE / DB 'SQLOLEDB' ICommandText :: Возвращено выполнение 0x80040e31: Исполнение прервано поставщиком, поскольку достигнут предел ресурса.].

Однако, когда я запускаю тот же запрос из той же базы данных (не из удаленной) в интерактивном окне запроса с жестко заданной датой:

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = '1/20/2012'

Возвращается через 30 секунд.

Локальный сервер - SQLSERVER 2008, удаленный - SQLSERVER 2000.

Мы сделали следующее безрезультатно:

  • Воссоздал сохраненный процесс.
  • sp_recompile для хранимого процесса
  • обновить статистику на dbo.accounts
  • удалил и пересоздал индексы на dbo.accounts
  • сбросил индекс на dbo.accounts и попробуй
  • DBCC FREEPROCCACHE и DBCC DROPCLEANBUFFERS на локальных и удаленных серверах
  • Перезагрузка удаленного сервера (непростой вариант на локальном)

Вопросов

  • Кто-нибудь может объяснить это странное поведение?
  • Любые предложения по другим вариантам его исправления?
Боб Пробст
источник

Ответы:

11

Вы можете включить флаг трассировки 7300, который может дать вам более подробное сообщение об ошибке

Сколько строк возвращает репрезентативный запрос? Насколько быстрым / надежным является сетевое соединение между двумя серверами?

Возможно, что для передачи большого набора данных требуется слишком много времени (сверх фактического времени запроса). Вы можете увеличить значение тайм-аута.

Вы можете попытаться изменить настройку тайм-аута следующим образом:

Установите время ожидания удаленного входа в систему на 300 секунд:

sp_configure 'remote login timeout', 300
go 
reconfigure with override 
go 

Установите время ожидания удаленного запроса на 0 (бесконечное ожидание):

sp_configure 'remote query timeout', 0 
go 
reconfigure with override 
go 

Обновление : SQL Server 2012 SP1 иSELECT более поздние версии : пользователи с разрешениями смогут получить доступ, DBCC SHOW_STATISTICSчто улучшит производительность только для чтения на связанных серверах. Ссылка: https://msdn.microsoft.com/en-us/library/ms174384(v=sql.110).aspx

Обновление : вы правы, говоря, что это не размер данных или скорость соединения. В моей туманной памяти прозвенел звонок, и я вспомнил, где видел его: медленно в приложении, быстро в SSMS? (Проблема со связанными серверами). Это не перехват параметров, а сама статистика отсутствует (из-за разрешений), из-за чего используется неверный план запроса:

Вы можете видеть, что оценки разные. Когда я работал как sysadmin, оценка составляла 1 строку, что является правильным числом, поскольку в Northwind нет заказов, где идентификатор заказа превышает 20000. Но когда я работал как обычный пользователь, оценка составляла 249 строк. Мы признаем это конкретное число как 30% от 830 заказов, или оценку операции неравенства, когда оптимизатор не располагает информацией. Ранее это происходило из-за неизвестного значения переменной, но в этом случае нет переменной, которая может быть неизвестна. Нет, сами статистические данные отсутствуют.

Пока запрос обращается только к таблицам на локальном сервере, оптимизатор всегда может получить доступ к статистике для всех таблиц в запросе; нет никаких дополнительных проверок разрешений. Но это не так с таблицами на связанном сервере. Когда SQL Server обращается к связанному серверу, не существует секретного протокола, который используется только для межсерверного взаимодействия. Нет, вместо этого SQL Server использует стандартный интерфейс OLE DB для связанных серверов, будь то другие экземпляры SQL Server, Oracle, текстовые файлы или ваш домашний источник данных, и подключается, как и любой другой пользователь. Точный способ получения статистики зависит от источника данных и соответствующего поставщика OLE DB. В этом случае поставщиком является собственный клиент SQL Server, который получает статистику в два этапа. (Вы можете увидеть это, запустив Profiler на удаленном сервере). Сначала провайдер запускает процедуру sp_table_statistics2_rowset, которая возвращает информацию о статистике столбцов, а также их количество элементов и их плотность. На втором этапе поставщик запускает команду DBCC SHOW_STATISTICS, которая возвращает полную статистику распространения. (Мы рассмотрим эту команду более подробно позже в этой статье.) Вот подвох: для запуска DBCC SHOW_STATISTICS вы должны быть членом роли сервера sysadmin или любой из ролей базы данных db_owner или db_ddladmin.

И именно поэтому я получил разные результаты. Когда я работал как sysadmin, я получил полную статистику распределения, которая показала, что нет строк с идентификатором заказа> 20000, и оценка составляла одну строку. (Напомним, что оптимизатор никогда не принимает нулевые строки из статистики.) Но при работе в качестве обычного пользователя DBCC SHOW_STATISTICS не удалось с ошибкой разрешения. Эта ошибка не распространялась, но вместо этого оптимизатор признал, что статистики не было, и использовал предположения по умолчанию. Так как он получил информацию о количестве элементов, он узнал, что в удаленной таблице 830 строк, откуда оценка в 249 строк.

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

  • Вы можете добавить пользователей к роли db_ddladmin, но, поскольку это дает им право добавлять и удалять таблицы, это не рекомендуется.

  • По умолчанию, когда пользователи подключаются к удаленному серверу, они подключаются как они сами, но вы можете настроить сопоставление имени входа с помощью sp_addlinkedsrvlogin, чтобы пользователи сопоставлялись с учетной записью прокси, которая имеет членство в db_ddladmin. Обратите внимание, что эта учетная запись-посредник должна быть учетной записью SQL, поэтому это не вариант, если на удаленном сервере не включена проверка подлинности SQL. Это решение также несколько сомнительно с точки зрения безопасности, хотя оно лучше предыдущего предложения.

  • В некоторых случаях вы можете переписать запрос с помощью OPENQUERY для принудительной оценки на удаленном сервере. Это может быть особенно полезно, если запрос включает несколько удаленных таблиц. (Но это также может иметь неприятные последствия, поскольку оптимизатор теперь получает еще меньше статистической информации с удаленного сервера.)

  • Конечно, вы могли бы использовать всю совокупность советов и планов, чтобы получить план, который вы хотите.

  • Наконец, вы должны спросить себя, нужен ли этот доступ к связанному серверу. Может быть, базы данных могут быть на одном сервере? Могут ли данные быть скопированы? Какое-то другое решение?

Митч Пшеничный
источник
Возвращает около 140 тыс. Записей. но так как он работает просто отлично, когда значение даты жестко закодировано, я не могу думать о проблеме ввода-вывода или сети, которая так сильно повлияет на параметризованную версию. Моя интуиция говорит, что запрос передается на удаленный сервер, и удаленный оптимизатор каким-то образом выбирает неверный план запроса, когда он не может понять параметр. Но переиндексация и очистка кеша / буферов должны исправить это (я полагаю). Я посмотрю на тайм-ауты, чтобы посмотреть, сможем ли мы хотя бы вернуть его. Спасибо
1
Отличный ответ и точно объяснил проблему, с которой я столкнулся, спасибо. Я бы добавил, что, согласно MSDN , начиная с SQL2012 SP1 и выше, пользователи с SELECTразрешениями смогут получить доступ, DBCC SHOW_STATISTICSчто повысит производительность только для чтения на связанных серверах без ущерба для безопасности.
Стив Петтифер
2

Что происходит, когда вы пытаетесь это сделать (то есть явно указывать, что следует запускать на удаленном сервере) ?:

select [fields]
into dbo.current_accounts
from OPENQUERY(linkedserver, 'SELECT [fields] FROM database.dbo.accounts where date = ''1/20/2012''');

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

Gareth
источник
1

Поскольку это проблема с ресурсами, пул памяти вне сервера SQL, используемый для загрузки внешних драйверов, и CLR могут быть близки к своему пределу. По умолчанию это 256 МБ. Чтобы обойти это, я предлагаю вам перейти к диспетчеру конфигурации сервера SQL, вкладке «Дополнительно» и добавить опцию -g в конец параметров запуска .ie; -g1024, а затем перезапустить службу SQL Server. Я обычно делаю это, так как мы используем большое количество связанных серверов. http://msdn.microsoft.com/en-us/library/ms190737.aspx

nopol
источник
1

У меня есть две идеи, которые могут помочь. Я также расскажу вам, что мне не повезло с производительностью выполнения запросов к связанным серверам. Поэтому моя первая рекомендация - избегать этого, если можете.

Моя первая идея - установить хранимую процедуру в блок SQL Server 2000, указав ссылку на локальный сервер. Затем вы можете выполнить хранимую процедуру удаленно.

exec linkedserver.database.dbo.Get_Accounts

Если вы можете пойти по этому пути, это должно значительно улучшить производительность.

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

Джефф Сивер
источник