Почему запрос ODBC к MSSQL 2008SP2 будет в 100 раз дольше, чем тот же запрос в Studio? - PullRequest
4 голосов
/ 08 февраля 2012

У меня действительно странный запрос, включающий объединение в сложное представление. Я проанализировал эту черту, построил несколько индексов и заставил запрос работать менее чем за секунду при запуске из MSSQL Management Studio. Однако при запуске из Perl через ODBC тот же запрос возвращает около 80 секунд.

Я бросил в это почти 8 часов, и это продолжает сбивать меня с толку. За это время я зарегистрировал запрос из Perl и дословно скопировал его в Studio, обернул его в хранимую процедуру (что делает его непротиворечивым за 2,5 минуты у ОБА клиентов), я прогуглил ODBC & MSSQL-запрос Кэши, я наблюдал за выполнением запроса через Activity Monitor (он проводит большую часть своего времени в общем состоянии ожидания SLEEP_TASK) и Profiler (оператор SELECT получает одну строку, которая не отображается, пока он не завершится), и я начал читать о узких местах производительности.

Я не заметил этой проблемы с другими запросами Perl, и, к сожалению, у нас нет администратора сайта. Я программист, который сделал некоторый DBA, но я чувствую, что нащупываю в темноте с этим. Мое предположение состоит в том, что в Studio есть какой-то кэш запросов, доступ к которому клиент ODBC не может получить, но перезапуск Studio не делает первое выполнение запроса более длительным, поэтому не похоже, что это происходит только потому, что каждое новое соединение ODBC начинается с пустого кэша.

Не вдаваясь в определения представлений, базовый запрос очень прост:

SELECT * FROM VIEW1 LEFT OUTER JOIN VIEW2 WHERE SECTION = ? AND ID = ?

Задержка исчезает, когда я опускаю VIEW2, но мне нужны данные из этого представления. Я уже трижды переписывал представление, пытаясь упростить и повысить эффективность, но это выглядит как тупик, так как запрос отлично выполняется из Studio. Запрос возвращает только одну строку, но даже удаление критерия идентификатора и выбор всех строк 56 КБ для всего раздела занимает всего 40 секунд из Studio. Есть другие идеи?

Изменить 2/8: Ссылка на статью @Remus Rusanu была довольно ясной, но, боюсь, это не совсем применимо. Теперь кажется довольно ясным, что это вовсе не ODBC, но когда я жестко кодирую аргументы, а не параметризую их, я получаю разные планы выполнения. Я могу воспроизвести это в SSMS:

SELECT * FROM VIEW1 LEFT OUTER JOIN VIEW2 WHERE SECTION = 'a' AND ID = 'b'

в 100 раз быстрее

DECLARE @p1 VARCHAR(8), @p2 VARCHAR(3)
SET @p1 = 'a'
SET @p2 = 'b'
SELECT * FROM VIEW1 LEFT OUTER JOIN VIEW2 WHERE SECTION = @p1 AND ID = @p2

К сожалению, я все еще затрудняюсь объяснить, почему первый должен получить план выполнения, который занимает на два порядка меньше времени, чем параметризованная версия, для любых значений SECTION & ID, которые я могу использовать. Это может быть недостатком в SQL Server, но кажется глупым, что входные данные известны в обоих местах, но один занимает намного больше времени. Если бы SQL-сервер пересчитывал параметризованный план с нуля каждый раз , как это должно быть для разных значений констант, которые я предоставляю, это было бы в 100 раз быстрее. Похоже, что ни один из вариантов RECOMPILE, предложенных в статье, тоже не помогает.

Я думаю, что @GSerg назвал это ниже. Мне еще предстоит доказать, что этого не происходит с оконной функцией, используемой внешне для представления, но он описывает то же самое, и расхождение во времени остается непонятным.

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

Ответы [ 3 ]

3 голосов
/ 09 февраля 2012

Как объяснил Мартин Смит , это проблема с предикатом push в SQL Server, которая не была исправлена ​​полностью.

Как предлагается в ответах и ​​комментариях в связанном вопросе, вы можете либо

  • Обернуть запрос во что-то, что добавляет option(recompile)
  • Преобразовать его в табличную функцию.
  • Прикрепить план плана с помощью option (recompile)
1 голос
/ 08 февраля 2012

Сравните планы для двух запросов и проверьте настройки SET для каждого соединения (вы можете сделать это, посмотрев в sys.dm_exec_sessions). Могу поспорить, вы увидите разницу в quoted_identifier, ansi_nulls или arithabort (или, возможно, все три). Это обычно вызывает огромные различия в плане выполнения. Вы должны иметь возможность установить эти параметры вручную в своей версии ODBC, чтобы соответствовать параметрам, которые используются Management Studio.

Некоторые связанные вопросы - могут быть другие неясные обстоятельства, которые вы захотите проверить:

Запрос SQL медленный в приложении .NET, но мгновенный в SQL Server Management Studio

Запрос SQL Server Медленный из PHP, но БЫСТРЫЙ из SQL Mgt Studio - ПОЧЕМУ?

Время ожидания запроса из веб-приложения, но отлично работает из студии управления

Быстрая хранимая процедура SQL Server 2005 в SSMS медленно от VBA

1 голос
/ 08 февраля 2012

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

В SSMS нет «кэша», к которому ODBC не может получить доступ.Просто вы получаете разные планы выполнения в SSMS и ODBC, либо из-за перехвата параметров, либо из-за правил приоритета типа данных.Прочтите связанную статью, в ней есть как средства для выявления проблемы, так и рекомендации по ее устранению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...