запрос sql server выполняется медленно с java
у меня есть программа java, которая запускает кучу запросов к базе данных sql server. Первый из них, который запрашивает представление, возвращает около 750k записей. Я могу запустить запрос через SQL server management studio, и я получаю результаты примерно за 30 секунд. тем не менее, я запустил программу вчера вечером. когда я проверил его сегодня утром, этот запрос все еще не вернул результаты обратно в программу java, примерно через 15 часов.
у меня есть доступ к базе данных, чтобы сделать почти все, что я хочу, но я действительно не уверен, как начать отлаживать это. Что нужно сделать, чтобы выяснить, что вызывает такую ситуацию? Я не dba, и я не близко знаком с набором инструментов sql server, поэтому более подробно вы можете дать мне о том, как сделать то, что вы могли бы предложить, было бы оценено.
вот код
stmt = connection.createStatement();
clientFeedRS = stmt.executeQuery(StringBuffer.toString());
EDIT1:
Ну, прошло некоторое время, и это отвлеклось, но эта проблема вернулась. Я заглянул в обновление с драйвера jdbc v 1.2 до 2.0, но мы застряли на jdk 1.4, а v 2.0 требует jdk 1.5, так что это не стартер. Теперь я смотрю на свойства строки подключения. Я вижу 2, что может быть полезным.
SelectMethod=cursor|direct
responseBuffering=adaptive|full
в настоящее время, с задержкой проблема, я бегу с курсором как selectMethod, и по умолчанию для responseBuffering, который полон. Может ли помочь изменение этих свойств? если да,то каковы были бы идеальные условия? Я думаю, основываясь на том, что могу. найдите в интернете, что использование метода прямого выбора и буферизации адаптивного ответа может решить мою проблему. есть мысли?
EDIT2:
Ну, я закончил изменение обоих этих параметров строки подключения, используя метод выбора по умолчанию (direct) и указав responseBuffering как адаптивный. Это в конечном итоге работает лучше всего для меня и облегчает проблемы с задержкой, которые я видел. спасибо за помощь.
12 ответов
убедитесь, что драйвер JDBC настроен на использование прямого соединения, а не соединения на основе cusror. Вы можете опубликовать URL-адрес подключения JDBC, если вы не уверены.
убедитесь, что вы используете только прямой, только для чтения результирующий набор (это значение по умолчанию, если вы его не устанавливаете).
и убедитесь, что вы используете обновленные драйверы JDBC.
Если все это не работает, то вы должны посмотреть на SQL profiler и попытаться захватить sql-запрос как драйвер jdbc выполняет инструкцию и запускает эту инструкцию в среде management studio, чтобы посмотреть, есть ли разница.
кроме того, поскольку вы вытягиваете так много данных, вы должны попытаться убедиться, что у вас нет замедления сбора памяти/мусора на JVM (хотя в этом случае это действительно не объясняет несоответствие времени).
У меня была аналогичная проблема с очень простым запросом (SELECT . ОТ. ГДЕ. = ) занимает до 10 секунд, чтобы вернуть одну строку при использовании соединения jdbc в Java, принимая только 0.01 s в sqlshell. Проблема была той же, использовал ли я официальный драйвер MS SQL или драйвер JTDS.
решение состояло в том, чтобы настроить это свойство в url JDBC : sendStringParametersAsUnicode=false
полный пример, если вы используете MS Официальный драйвер SQL : jdbc:sqlserver://yourserver;instanceName=yourInstance;databaseName=yourDBName;sendStringParametersAsUnicode=false;
инструкции при использовании различных драйверов jdbc и более подробной информации о проблеме здесь: http://emransharif.blogspot.fr/2011/07/performance-issues-with-jdbc-drivers.html
SQL Server отличает свои типы данных, которые поддерживают Unicode от тех, которые просто поддержка ASCII. Например, символьными типами данных, поддерживающими Юникод, являются nchar, nvarchar, longnvarchar, где в качестве их частей счетчика ASCII являются char, varchar и longvarchar соответственно. По умолчанию все драйверы JDBC корпорации Майкрософт отправляют строки в формате Unicode на SQL Server, независимо от того, поддерживает ли тип данных соответствующего столбца, определенного в SQL Server, Unicode или нет. В случае, когда типы данных столбцов поддерживают Unicode, все гладко. Но, в в случаях, когда типы данных столбцов не поддерживают Unicode, возникают серьезные проблемы с производительностью, особенно во время выборки данных. SQL Server пытается преобразовать типы данных, отличные от unicode в таблице, в типы данных unicode перед выполнением сравнения. Более того, если индекс существует в столбце, отличном от unicode, он будет проигнорирован. Это в конечном итоге приведет к сканированию всей таблицы во время выборки данных, что резко замедлит поисковые запросы.
в моем случае у меня было 30M + записей в столе, из которого я искал. Продолжительность выполнения запроса составила от более чем 10 секунд до приблизительно 0,01 с после применения свойства.
надеюсь, что это поможет кому-то !
похоже, это не относится к вашей конкретной ситуации, но я хотел бы предоставить другое возможное объяснение для кого-то, кто ищет эту проблему.
У меня просто была аналогичная проблема, когда запрос, выполненный непосредственно в SQL Server, занял 1 минуту, а тот же запрос занял 5 минут через Java prepared statemnent. Я отследил это до того, что это было сделано как подготовленное заявление.
когда вы выполняете запрос непосредственно в SQL Server, вы обеспечивая это параметризованный запрос, в котором он знает все критерии поиска во время оптимизации. В моем случае мои критерии поиска включали диапазон дат, и SQL server смог посмотреть на него, решить "что диапазон дат огромен, давайте не будем использовать индекс дат", а затем он выбрал что-то намного лучше.
когда я выполняю тот же запрос через подготовленный Java оператор, в то время, когда SQL Server оптимизирует запрос, вы еще не предоставили ему ни одного из значений параметров, поэтому он должен угадать, какой индекс использовать. В случае моего диапазона дат, если он оптимизируется для малого диапазона, а я даю ему большой диапазон, он будет работать медленнее, чем мог бы. Аналогично, если он оптимизируется для большого диапазона, а я даю ему маленький, он снова будет работать медленнее, чем мог бы.
чтобы продемонстрировать, что это действительно проблема, в качестве эксперимента я попытался дать ему подсказки о том, что оптимизировать для использования опции "оптимизировать для" SQL Server. Когда я сказал ему использовать крошечный диапазон дат, мой Java-запрос (который фактически имел широкий диапазон дат) фактически занял в два раза больше времени, чем раньше (10 минут, в отличие от 5 минут до этого, и в отличие от 1 минуты в SQL Server). Когда я сказал ему свои точные даты для оптимизации, время выполнения было идентичным между подготовленным Java-оператором.
поэтому моим решением было жестко закодировать точные даты в запросе. Это сработало для меня, потому что это было всего лишь одноразовое заявление. Подготовленное заявление не предназначалось для повторно используется, но только для параметризации значений, чтобы избежать SQL-инъекции. Поскольку эти даты исходили из java.язык SQL.Объект даты, мне не нужно было беспокоиться о моих значениях даты, содержащих код инъекции.
однако для оператора, который необходимо использовать повторно, жесткое кодирование дат не будет работать. Возможно, лучшим вариантом для этого было бы создать несколько подготовленных операторов, оптимизированных для разных диапазонов дат (один для дня, один для недели, один для месяца, один для года и один в течение десятилетия...или, может быть, вам нужно только 2 или 3 варианта...Я не знаю), а затем для каждого запроса выполните один подготовленный оператор, диапазон времени которого лучше всего соответствует диапазону в фактическом запросе.
конечно, это работает хорошо, только если ваши диапазоны дат равномерно распределены. Если 80% ваших записей были за последний год, а 20% - за предыдущие 10 лет, то выполнение "нескольких запросов на основе размера диапазона" может быть не лучшим. Вам придется оптимизировать запросы основываясь на определенных диапазонах или что-то в этом роде. Вам нужно будет выяснить это через пробную ошибку.
если запрос параметризован, это может быть отсутствующий параметр или параметр, заданный с неправильной функцией, например setLong для строки и т. д.
Попробуйте запустить запрос со всеми параметрами вшитые в тело запроса без каких-либо ?
видеть это проблема.
Я знаю, что это старый вопрос, но поскольку это один из первых результатов при поиске этой проблемы, я решил, что должен опубликовать то, что сработало для меня. У меня был запрос, который занял менее 10 секунд, когда я использовал драйвер JDBC SQL Server, но более 4 минут при использовании jTDS. Я пробовал все предложения, упомянутые здесь, и ничто из этого не имело никакого значения. Единственное, что сработало, это добавление этого в URL"; prepareSQL=1"
посмотреть здесь дополнительные
оттягивание этого количества данных потребует много времени. Вероятно, вы должны найти способ не требовать столько данных в своем приложении в любой момент времени. Страница данных или использовать загрузка например. Без более подробной информации о том, что вы пытаетесь достичь, трудно сказать.
тот факт, что он быстр при запуске из management studio, может быть вызван неправильно кэшированным планом запроса и устаревшими индексами (скажем, из-за большого импорта или удаления). Он быстро возвращает все записи 750K в SSMS?
попробуйте перестроить индексы (или, если это займет слишком много времени, обновите статистику); и, возможно, очистите кэш процедур (будьте осторожны, если это производственная система...): DBCC FREEPROCCACHE
начать отладку этого, было бы хорошо, чтобы определить, является ли проблемой в базе данных или в приложение. Вы пытались изменить запрос так, чтобы он возвращал гораздо меньший результат? Если это не вернется, я бы предложил таргетинг на способ доступа к БД с Java.
попробуйте настроить размер выборки оператора и попробуйте selectMethod курсора
http://technet.microsoft.com/en-us/library/aa342344 (SQL.90).aspx
У нас были проблемы с большими результирующими наборами с использованием mysql и необходимо было сделать его потоком результирующего набора, как описано в следующей ссылке.
http://helpdesk.objects.com.au/java/avoiding-outofmemoryerror-with-mysql-jdbc-driver
цитата из руководства MS Adaptive buffer:
избегайте использования свойства строки подключения selectMethod=cursor, чтобы приложение могло обрабатывать очень большой результирующий набор. Функция адаптивной буферизации позволяет приложениям обрабатывать очень большие результирующие наборы только для чтения без использования курсора сервера. Обратите внимание, что при установке selectMethod=cursor, все только вперед, только для чтения результирующие наборы, созданные этим соединением, влияют. Другими словами, если ваш приложение обычно обрабатывает короткие результирующие наборы с несколькими строками, создавая, читая и закрывая курсор сервера для каждого результирующего набора, будет использовать больше ресурсов как на стороне клиента, так и на стороне сервера, чем в случае, когда selectMethod не установлен в cursor.
и
есть несколько случаев, когда использование selectMethod=cursor вместо responseBuffering=adaptive было бы более полезным, например:
Если ваш приложение обрабатывает только прямой, только для чтения результирующий набор медленно, например, чтение каждой строки после ввода пользователем, используя selectMethod=cursor вместо responseBuffering=adaptive может помочь уменьшить использование ресурсов SQL Server.
Если ваше приложение обрабатывает два или более наборов результатов только для чтения в одно и то же время на одном соединении, использование selectMethod=cursor вместо responseBuffering=adaptive может помочь уменьшить объем памяти, требуемый драйвером при обработке этих результирующих наборов.
в обоих случаях необходимо учитывать накладные расходы на создание, чтение и закрытие курсоров сервера.
подробнее:http://technet.microsoft.com/en-us/library/bb879937.aspx
иногда это может быть связано с тем, как параметры привязываются к объекту запроса. Я обнаружил, что следующий код очень медленный при выполнении из java-программы.
Query query = em().createNativeQuery(queryString)
.setParameter("param", SomeEnum.DELETED.name())
Как только я удаляю параметр "deleted" и напрямую добавляю эту строку "DELETED" в запрос, он становится супер быстрым. Это может быть связано с тем, что SQL server ожидает, что все параметры будут привязаны к решению оптимизированного плана.
занимает ли это аналогичное количество времени с SQLWB? Если версия Java намного медленнее, то я бы проверил пару вещей:
- вы shoudl получить лучшую производительность с только вперед, только для чтения ResultSet.
- Я помню, что старые драйверы JDBC из MSFT были медленными. Убедитесь, что вы используете последнюю-Н-величайший. Я думаю, что есть общий SQL Server один и один специально для SQL 2005.