Почему удаленное выполнение запроса может привести к его приостановке? - PullRequest
1 голос
/ 26 февраля 2012

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

У меня есть таблица на SQL Server 2005 с большим количеством столбцов, может быть, 20, но с огромным количеством строк (десятки, более вероятно, сотни миллионов). Чтобы упростить объем работы JPA, которую мне нужно было сделать, чтобы получить к ней доступ, я создал представление, содержащее интересующие меня биты. Представление было создано как:

SELECT bigtable.ID, bigtable.external_identification, mediumtable.hostname,
    CONVERT(VARCHAR, bigtable.datefield, 121) AS datefield
FROM schema.bigtable JOIN schema.mediumtable ON bigtable.joinID = mediumtable.ID;

Когда я хочу выбрать из вида, я делаю:

SELECT * FROM vwTable WHERE external_identification = 'some string';

Это прекрасно работает в SQL Management Studio. Столбец external_identification имеет неуникальный некластеризованный индекс в bigtable. Это также отлично работало с нашей удаленно выполняющейся Java-программой в нашей тестовой среде. Теперь, когда мы находимся в одном или двух днях от производства, код немного изменился (хотя фундаментальный JPA NamedQuery все еще прост), но у нас новая установка SQLServer на новом оборудовании; тестовая версия была на 32-битной одноядерной машине, новое оборудование - 64-битной многоядерной.

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

SELECT status, command, wait_type, last_wait_type FROM sys.dm_exec_requests;

подтвердил, что запрос запущен, но показал его в состоянии:

suspended, SELECT, CXPACKET, CXPACKET

столько, сколько я хотел ждать. Всякий раз, когда я запускал один и тот же запрос из Management Studio, он выполнялся немедленно. Поэтому я провел небольшое исследование и выяснил, что это связано с ожиданием начала / завершения какой-то параллельной операции. Пытаясь обойти это, я установил для сервера MAXDOP значение 1 (отключенный параллелизм). После этого запрос все еще зависает, но sys.dm_exec_requests будет отображать:

suspended, SELECT, PAGEIOLATCH_SH, PAGEIOLATCH_SH

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

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

Но я подозреваю, что цепляюсь за соломинку. Я не администратор баз данных, и каждый раз, когда мне приходится взаимодействовать с SQL Server, не обращаясь к нему, это сбивает с толку мою интуицию. У кого-нибудь есть идеи, почему запрос, выполненный удаленно, немедленно перешел бы в состояние ожидания, в то время как тот же самый запрос локально был бы выполнен немедленно?

Ответы [ 2 ]

2 голосов
/ 27 февраля 2012

Ух ты, этот поймал меня прямо с левого поля.Оказывается, что по умолчанию драйвер MSSQL JDBC отправляет свои типы данных String как Unicode, которые таблица / представление могут быть не готовы обрабатывать специально.В нашем случае столбцов и индексов не было, поэтому MSSQL будет выполнять полное сканирование таблицы для каждого поиска.

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

Когда я добавил этот маленький параметр в конец строки подключения JDBC:

jdbc:sqlserver://[IP]:1433;databaseName=[db];sendStringParametersAsUnicode=false

все сразу и волшебным образом заработало.Извините за слегка вводящий в заблуждение вопрос (я даже не упомянул JPA), но я понятия не имел, в чем причина, и действительно верил, что это что-то на стороне SQL Server.Диспетчер задач не сообщал о высокой загрузке ЦП / памяти, пока запрос был приостановлен, поэтому я просто подумал, что он работает на холостом ходу, несмотря на то, что он действительно загружен на жестком диске.где я наткнулся на решение, в http://server.pramati.com/blog/2010/06/02/perfissues-jdbcdrivers-mssqlserver/.Спасибо, Эд, за этот подробный снимок в темноте - это, возможно, и не было проблемой, но я, конечно, многому научился (и быстро!) Относительно мелких деталей MSSQL!

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

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

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

Вы можете узнать, какие параметры использует ваше приложение, запустив по умолчанию трассировку SQL Server profiler trace для сервера; первой командой после создания соединения будет несколько SET... опций:

SET DATEFORMAT dmy
SET ANSI_NULLS ON
...

Я подозреваю, что этот список будет отличаться между вашим приложением и вашим подключением к SSMS - общий кандидат SET ARITHABORT {ON|OFF}, поскольку он является частью ключа кэшированного плана.
Если вы выполняете команды SET... в окне SSMS до выполнения запроса, то должен быть выбран тот же (плохой) план, который используется приложением.

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

SELECT * FROM vwTable WHERE external_identification = 'some string' OPTION (RECOMPILE);

Предполагая, что вы можете воспроизвести плохую производительность SSMS с помощью описанных выше шагов, вы сможете проверить это там.
Помните, что это может иметь отрицательные последствия для производительности, если запрос выполняется очень часто (поскольку каждая перекомпиляция требует ЦП) - это зависит от рабочей нагрузки вашего приложения и потребует тестирования.

Пара других мыслей:

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

Вы должны снова включить параллелизм, отключив серверный MAXDOP=1, так как это ограничит производительность вашей системы в целом. Проблема почти наверняка в плане запроса, а не в параллелизме

Вам также необходимо остерегаться последствий добавления индексов к представлению - это эффективно материализует представление, что (с учетом размера таблицы) потребует больших затрат на хранение - индексы также необходимо будет поддерживать когда INSERT / UPDATE / DELETE операторы имеют место на базовой таблице. Индексирование представления, вероятно, не нужно, учитывая, что (из SSMS) вы знаете, что запрос может быть выполнен.

...