У меня действительно странный запрос, включающий объединение в сложное представление. Я проанализировал эту черту, построил несколько индексов и заставил запрос работать менее чем за секунду при запуске из 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 назвал это ниже. Мне еще предстоит доказать, что этого не происходит с оконной функцией, используемой внешне для представления, но он описывает то же самое, и расхождение во времени остается непонятным.
Если у меня не хватит времени, чтобы поработать над этим, я постараюсь адаптировать некоторые из советов статьи и навязать план постоянного выполнения для параметризованной версии, но, похоже, очень многое из того, что должно быть ненужные неприятности.