SQL Server запрос работает медленно из Java

java sql-server-2005 jdbc connection-string

18070 просмотра

13 ответа

У меня есть Java-программа, которая выполняет кучу запросов к базе данных SQL Server. Первый из них, который запрашивает представление, возвращает около 750 тыс. Записей. Я могу выполнить запрос через SQL Server Studio Studio, и я получаю результаты примерно через 30 секунд. Тем не менее, я запустил программу для запуска прошлой ночью. когда я проверил его этим утром, этот запрос все еще не дал результатов обратно в программу Java, примерно через 15 часов.

У меня есть доступ к базе данных, чтобы делать все, что я хочу, но я действительно не знаю, как начать отлаживать это. Что нужно сделать, чтобы выяснить, что является причиной такой ситуации? Я не dba, и я не очень хорошо знаком с набором инструментов сервера sql, так что более подробная информация, которую вы можете дать мне о том, как сделать то, что вы предлагаете, будет принята с благодарностью.

вот код

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 как адаптивный. Это в конечном итоге работает лучше для меня и устраняет проблемы с задержкой, которые я видел. Спасибо за помощь.

Автор: shsteimer Источник Размещён: 17.05.2019 02:55

Ответы (13)


4 плюса

Решение

Убедитесь, что ваш драйвер JDBC сконфигурирован для использования прямого соединения, а не соединения cusror. Вы можете опубликовать свой URL-адрес подключения JDBC, если вы не уверены.

Убедитесь, что вы используете набор результатов только для пересылки и только для чтения (это значение по умолчанию, если вы его не устанавливаете).

И убедитесь, что вы используете обновленные драйверы JDBC.

Если все это не работает, вы должны взглянуть на SQL Server Profiler и попытаться перехватить SQL-запрос, поскольку драйвер jdbc выполняет оператор, и запустить этот оператор в студии управления и посмотреть, есть ли разница.

Кроме того, поскольку вы извлекаете так много данных, вы должны быть уверены, что у вас нет каких-либо замедлений памяти / сбора мусора в JVM (хотя в данном случае это не объясняет расхождения во времени).

Автор: Yishai Размещён: 07.06.2009 04:18

22 плюса

У меня была похожая проблема с очень простым запросом (SELECT. FROM. WHERE =.), Который занимал до 10 секунд, чтобы вернуть одну строку при использовании соединения jdbc в Java, в то время как в sqlshell требовалось всего 0,01 секунды. Проблема была той же, использую ли я официальный драйвер 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. Например, символьными типами данных, которые поддерживают Unicode, являются nchar, nvarchar, longnvarchar, где в качестве счетчиков ASCII используются char, varchar и longvarchar соответственно. По умолчанию все драйверы Microsoft JDBC отправляют строки в формате Unicode на SQL Server, независимо от того, поддерживает ли тип данных соответствующего столбца, определенного в SQL Server, Unicode или нет. В случае, когда типы данных столбцов поддерживают Unicode, все гладко. Но в тех случаях, когда типы данных столбцов не поддерживают Unicode, серьезные проблемы с производительностью возникают, особенно во время выборки данных. SQL Server пытается преобразовать типы данных, отличные от Юникод в таблице, в типы данных Юникод перед выполнением сравнения. Более того, если для столбца не в Юникоде существует индекс, он будет проигнорирован. Это в конечном итоге приведет к сканированию всей таблицы во время выборки данных, что значительно замедлит поисковые запросы.

В моем случае у меня было 30 миллионов записей в таблице, из которой я искал. Продолжительность выполнения запроса увеличилась с более чем 10 секунд до приблизительно 0,01 с после применения свойства.

Надеюсь, это поможет кому-то!

Автор: Khopa Размещён: 30.09.2015 01:36

7 плюса

Возможно, это не относится к вашей конкретной ситуации, но я хотел дать другое возможное объяснение тому, кто ищет эту проблему.

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

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

Когда я выполняю тот же запрос с помощью подготовленного Java-оператора, в то время, когда SQL Server оптимизирует запрос, вы еще не предоставили ему ни одного из значений параметров, поэтому он должен угадать, какой индекс использовать. В случае моего диапазона дат, если он оптимизируется для небольшого диапазона, и я задаю ему большой диапазон, он будет работать медленнее, чем мог бы. Точно так же, если он оптимизируется для большого диапазона, а я даю ему маленький, он снова будет работать медленнее, чем мог бы.

Чтобы продемонстрировать, что это действительно было проблемой, в качестве эксперимента я попытался дать подсказку о том, что оптимизировать для использования опции «OPTIMIZE FOR» в SQL Server. Когда я сказал ему использовать крошечный диапазон дат, мой Java-запрос (который на самом деле имел широкий диапазон дат) фактически занимал в два раза больше времени, чем раньше (10 минут, по сравнению с 5 минутами раньше, и 1 минутой в SQL Server). ). Когда я сообщил точные даты для оптимизации, время выполнения было одинаковым для подготовленного Java-оператора.

Поэтому я решил жестко запрограммировать точные даты в запросе. Это сработало для меня, потому что это было разовое заявление. PreparedStatement не предназначался для повторного использования, а просто для параметризации значений, чтобы избежать внедрения SQL. Поскольку эти даты были получены из объекта java.sql.Date, мне не пришлось беспокоиться о значениях дат, содержащих код внедрения.

Тем не менее, для заявления, которое нужно использовать повторно, жесткое кодирование дат не сработает. Возможно, лучшим вариантом для этого было бы создание нескольких подготовленных выписок, оптимизированных для разных диапазонов дат (один на день, один на неделю, один на месяц, один на год и один на десятилетие ... или, может быть, вы нужны только 2 или 3 варианта ... я не знаю) и затем для каждого запроса выполняйте один подготовленный оператор, временной диапазон которого лучше всего соответствует диапазону в реальном запросе.

Конечно, это работает только в том случае, если ваши диапазоны дат распределены равномерно. Если 80% ваших записей были в прошлом году, а 20% - разбросаны за предыдущие 10 лет, то выполнение «нескольких запросов на основе размера диапазона» может оказаться не лучшим решением. Вы должны оптимизировать свои запросы на основе определенных диапазонов или чего-то еще. Вы должны выяснить это через пробу ошибки.

Автор: ldkronos Размещён: 22.10.2014 01:39

3 плюса

Если запрос параметризован, это может быть отсутствующий параметр или параметр, который установлен с неверной функцией, например, setLong для строки и т. Д. Попробуйте выполнить свой запрос со всеми параметрами, жестко закодированными в теле запроса, без каких-либо сведений ?об этом. проблема.

Автор: Leon Fleysher Размещён: 04.01.2011 04:05

1 плюс

Я знаю, что это старый вопрос, но так как это один из первых результатов при поиске этой проблемы, я решил опубликовать то, что сработало для меня. У меня был запрос, который занимал менее 10 секунд при использовании драйвера JDBC для SQL Server, но более 4 минут при использовании jTDS. Я перепробовал все предложения, упомянутые здесь, и ни одно из них не имело никакого значения. Единственное, что сработало, это добавление этого в URL "; prepareSQL = 1"

Смотрите здесь для более

Автор: Sol Размещён: 02.01.2015 04:12

0 плюса

Для извлечения такого большого количества данных потребуется много времени. Вы, вероятно, должны найти способ не требовать столько данных в вашем приложении в любой момент времени. Страница данных или использовать ленивую загрузку, например. Без подробностей о том, чего вы пытаетесь достичь, трудно сказать.

Автор: JP Alioto Размещён: 07.06.2009 02:43

0 плюса

Тот факт, что он выполняется быстро из среды Management Studio, может быть вызван неверно кэшированным планом запросов и устаревшими индексами (скажем, из-за большого импорта или удаления). Возвращает ли он все 750K записей в SSMS быстро?

Попробуйте перестроить ваши индексы (или, если это займет слишком много времени, обновите статистику); и, возможно, очистить кэш процедур (будьте осторожны, если это производственная система ...):DBCC FREEPROCCACHE

Автор: Mitch Wheat Размещён: 07.06.2009 02:53

0 плюса

Чтобы начать отладку, было бы хорошо определить, находится ли проблемная область в базе данных или в приложении. Вы пытались изменить запрос так, чтобы он возвращал гораздо меньший результат? Если это не вернется, я бы посоветовал выбрать способ доступа к БД из Java.

Автор: akf Размещён: 07.06.2009 03:53

0 плюса

Попробуйте настроить размер выборки оператора и попробуйте выбрать метод курсора.

http://technet.microsoft.com/en-us/library/aa342344(SQL.90).aspx

У нас были проблемы с большими результирующими наборами, использующими mysql, и нам нужно было потоковую передачу результирующего набора, как описано в следующей ссылке

http://helpdesk.objects.com.au/java/avoiding-outofmemoryerror-with-mysql-jdbc-driver

Автор: objects Размещён: 07.06.2009 04:20

0 плюса

Цитата из руководства по адаптивному буферу MS:

Избегайте использования свойства строки подключения selectMethod = cursor, чтобы приложение могло обрабатывать очень большой набор результатов. Функция адаптивной буферизации позволяет приложениям обрабатывать очень большие наборы результатов только для пересылки и только для чтения без использования серверного курсора. Обратите внимание, что когда вы устанавливаете selectMethod = cursor, это влияет на все результирующие наборы только для пересылки и только для чтения, созданные этим соединением. Другими словами, если ваше приложение обычно обрабатывает короткие результирующие наборы с несколькими строками, создание, чтение и закрытие серверного курсора для каждого результирующего набора будет использовать больше ресурсов как на стороне клиента, так и на стороне сервера, чем в случае, когда selectMethod не установлен на курсор.

А также

В некоторых случаях было бы более целесообразно использовать selectMethod = cursor вместо responseBuffering = adaptive, например:

  • Если ваше приложение медленно обрабатывает набор результатов только для чтения и чтения, например, чтение каждой строки после некоторого пользовательского ввода, использование selectMethod = cursor вместо responseBuffering = adaptive может помочь сократить использование ресурсов SQL Server.

  • Если ваше приложение одновременно обрабатывает два или более набора результатов только для чтения и только для чтения на одном и том же соединении, использование selectMethod = cursor вместо responseBuffering = adaptive может помочь уменьшить объем памяти, требуемый драйвером при обработке этих наборов результатов.

В обоих случаях вам необходимо учесть затраты на создание, чтение и закрытие серверных курсоров.

Подробнее: http://technet.microsoft.com/en-us/library/bb879937.aspx

Автор: eugenevd Размещён: 13.03.2013 09:37

0 плюса

Иногда это может быть связано с тем, как параметры привязываются к объекту запроса. Я обнаружил, что следующий код работает очень медленно при выполнении из Java-программы.

Query query = em().createNativeQuery(queryString)                    
                .setParameter("param", SomeEnum.DELETED.name())

Как только я удаляю параметр «удаленный» и напрямую добавляю эту строку «УДАЛЕНО» к запросу, он становится очень быстрым. Это может быть связано с тем, что SQL-сервер ожидает, чтобы все параметры были связаны для определения оптимизированного плана.

Автор: Shehan Simen Размещён: 08.02.2018 03:02

0 плюса

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

У меня был запрос, который занимал около 3 секунд, когда я использовал SQL Server Management Studio (SSMS), но занимал 3,5 минуты при запуске с использованием драйвера jTDS JDBC через executeQueryметод.

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

Вот пример строки подключения:

jdbc:jtds:sqlserver://YourSqlServer.name:1433/DefaultDbName

Убедитесь, что у вас есть конец, /DefaultDbNameуказанный в строке подключения. Вот DefaultDbNameимя базы данных, с которой у ID пользователя, указанного для установления соединения JDBC, есть хотя бы db_datareaderроль базы данных. Если не указан, SQL Server по умолчанию использует masterбазу данных. Если идентификатор пользователя, используемый для установления соединения JDBC, играет publicроль только в базе данных master, запрос выполняется исключительно долго.

Я не знаю, почему это происходит. Однако я знаю, что в таких обстоятельствах используется другой план запросов. Я подтвердил это с помощью инструмента SQL Profiler.

Детали среды:

  • Версия SQL Server: 2016
  • Версия драйвера jTDS: 1.3.1
  • Версия Java: 11
Автор: Mody Размещён: 27.02.2019 11:47

-1 плюса

Это займет столько же времени с SQLWB? Если версия Java намного медленнее, я бы проверил несколько вещей:

  1. Вы получите лучшую производительность с помощью ResultSet только для чтения и только для чтения.
  2. Напомню, что старые драйверы JDBC от MSFT работали медленно. Убедитесь, что вы используете самую последнюю версию. Я думаю, что есть универсальный SQL Server один и один специально для SQL 2005.
Автор: Brian Reiter Размещён: 07.06.2009 03:53
Вопросы из категории :
32x32