Время выполнения SQL в сервлете Tomcat намного медленнее, чем в обычной программе Java.

Однако по необъяснимым причинам сегодня утром производительность увеличилась для двух моих запросов, которые раньше были медленными. Понятия не имею почему.
У меня нет прав на сервер, может кто-то что-то менял.
Проблемы больше нет.

В двух словах:

  • s.executeQuery(sql) работает очень медленно в сервлете tomcat на сервере
  • Тот же запрос отлично работает без сервлета (простая программа Java) на той же машине
  • Не все запросы в сервлете выполняются медленно. Только несколько больших делают
  • Тот же сервлет работает быстро на другой машине

ОБНОВЛЕНИЯ

Пожалуйста, читайте обновления под текстом!

У меня есть servlet, который выполняет запросы SQL и отправляет результаты через JSON. По какой-то причине выполнение некоторых запросов занимает огромное количество времени, но когда я запускаю их в любом клиенте Oracle SQL, они выполняются в кратчайшие сроки.

Я говорю о разнице в 1 секунду и 5 минут для одного и того же SQL (это не так сложно).

Как это можно объяснить? Есть ли способ улучшить производительность SQL-запроса на основе Java?

Я использую традиционный способ выполнения запросов:

java.sql.Connection conn = null;
java.sql.Statement s = null;
ResultSet rs = null;

String dbDriver = "oracle.jdbc.driver.OracleDriver";
String dbConnectionString = "jdbc:oracle:thin:@" + dbHost + ":" + dbPort + ":" + dbSid;

Class.forName(dbDriver).newInstance();
conn = DriverManager.getConnection(dbConnectionString, dbUser, dbPass);
s = conn.createStatement();
s.setQueryTimeout(9999);
rs = s.executeQuery(newStatement);
ResultSetMetaData rsmd = rs.getMetaData();

// Get the results
while (rs.next()) {
// collect the results
}

// close connections

Я пробовал с ojdbc14 и ojdbc6, но разницы не было.

ОБНОВЛЕНИЕ 1: я попробовал тот же SQL в локальном проекте Java (не сервлете) на своем клиентском компьютере и сразу же получил результаты. Итак, я предполагаю, что проблема связана с моим сервлетом или конфигурацией tomcat?

ОБНОВЛЕНИЕ 2: виновником действительно является rs = s.executeQuery(mySql); Вместо этого я попытался использовать подготовленный статемент, но разницы нет.

ОБНОВЛЕНИЕ 3: я создал новый сервлет, работающий на локальном Tomcat, и запрос возвращается быстро. Таким образом, проблема исходит от моего производственного сервера или конфигурации Tomcat. Любые идеи, какие элементы конфигурации могут повлиять на это?

ОБНОВЛЕНИЕ 4: я попробовал тот же код в обычной Java-программе вместо сервлета (все еще на том же сервере), и результаты приходят быстро. Следовательно, проблема исходит от самого сервлета (или Tomcat?). Пока не знаю, что делать, но я сузил его :)

ОБНОВЛЕНИЕ 5: Jstack показывает следующее (он начинается там, где находится мой сервлет, остальное я вырезал)

    "http-8080-3" daemon prio=3 tid=0x00eabc00 nid=0x2e runnable [0xaa9ee000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at oracle.net.ns.Packet.receive(Packet.java:311)
        at oracle.net.ns.DataPacket.receive(DataPacket.java:105)
        at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:305)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:249)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:171)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:89)
        at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:123)
        at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:79)
        at oracle.jdbc.driver.T4CMAREngineStream.unmarshalUB1(T4CMAREngineStream.java:429)
        at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:397)
        at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257)
        at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:587)
        at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:210)
        at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:30)
        at oracle.jdbc.driver.T4CStatement.executeForDescribe(T4CStatement.java:762)
        at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:925)
        at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1104)
        at oracle.jdbc.driver.OracleStatement.executeQuery(OracleStatement.java:1309)
        - locked <0xe7198808> (a oracle.jdbc.driver.T4CConnection)
        at oracle.jdbc.driver.OracleStatementWrapper.executeQuery(OracleStatementWrapper.java:422)
        

Значит, я застрял на java.net.SocketInputStream.socketRead0(Native Method)?


person Tim    schedule 11.06.2015    source источник
comment
Клиент находится на той же машине, что и клиент jdbc? Как насчет пакетирования?   -  person Jayan    schedule 11.06.2015
comment
вы сравниваете по одному признаку? Ваш код печатает набор результатов, делаете ли вы то же самое с клиентом SQL? Обычно запрос выполняется очень быстро, но передача данных и их отображение также занимают много времени. И кстати: вы должны использовать пул соединений. Вы проверили, возможно ли потрачено время на вход в систему? Еще один совет: вы можете использовать dbVisualizer для подключения к базе данных. Он написан на том же языке (Java), но оптимизирован. Таким образом, вы, возможно, увидите, связана ли проблема с Java/драйвером или вашим кодом.   -  person Marged    schedule 11.06.2015
comment
вы не используете подготовленные заявления, которые будут кэшировать ваш запрос. Пожалуйста, опубликуйте оба запроса, иначе мы не сможем помочь.   -  person Paizo    schedule 11.06.2015
comment
Используйте prepareStatement и установите значение fetchziseof из набора результатов около 1000, это уменьшит количество операций ввода-вывода.   -  person Kalyan Chavali    schedule 11.06.2015
comment
Какой именно клиент является любым клиентом Oracle SQL? Какие технологии используют эти клиенты?   -  person a_horse_with_no_name    schedule 11.06.2015
comment
Для уточнения: я использую Aqua Data Studio, но то же самое и с Toad. Другие (намного большие) запросы sql работают нормально. Кроме того, это не связано с количеством результатов. Мой запрос медленный даже с одним результатом. Я посмотрю на dbVisualizer, спасибо.   -  person Tim    schedule 11.06.2015
comment
ОБНОВЛЕНИЕ: я попробовал тот же SQL в локальном проекте Java (не в сервлете) и сразу же получил результаты. Итак, я предполагаю, что проблема связана с моим сервлетом или конфигурацией tomcat?   -  person Tim    schedule 11.06.2015
comment
ОБНОВЛЕНИЕ2: виновником действительно является rs = s.executeQuery(mySql); Вместо этого я попытался использовать подготовленный статемент, но разницы нет.   -  person Tim    schedule 11.06.2015
comment
Найден похожий случай: coderanch.com/t /625133/JDBC/базы данных/   -  person Tim    schedule 11.06.2015
comment
ОБНОВЛЕНИЕ 3: я создал новый сервлет, работающий на локальном Tomcat, и запрос быстро возвращается. Таким образом, проблема исходит от моего производственного сервера или конфигурации Tomcat. Любые идеи, какие элементы конфигурации могут повлиять на это?   -  person Tim    schedule 11.06.2015
comment
UPDATE4: я попробовал тот же код в обычной Java-программе вместо сервлета (все еще на том же сервере), и результаты приходят быстро. Следовательно, проблема исходит от самого сервлета (или Tomcat?). Пока не знаю, что делать, но я сузил его :)   -  person Tim    schedule 12.06.2015
comment
Возможно, проблема связана с пулом соединений. Проверьте конфигурацию кота.   -  person uhs    schedule 15.06.2015
comment
Уже проверил - стоит отметить, что мой конкретный сервлет не занимает много времени для всех SQL-запросов, только несколько более крупных (но все же они не такие сложные - вне сервлета они выполняются менее чем за секунду).   -  person Tim    schedule 15.06.2015


Ответы (5)


В некоторых случаях (не уверен, что это относится к вам) установка fetchSize для объекта Statement приводит к значительному повышению производительности. Это зависит от размера извлекаемого набора результатов.

Попробуйте поэкспериментировать с ним, установив значение больше, чем значение по умолчанию 10 для Oracle (см. "nofollow">эта ссылка).

См. Statement.setFetchSize. .

person siphiuel    schedule 11.06.2015
comment
Спасибо, но это ничего не изменило - person Tim; 11.06.2015

Учитывая ваши симптомы, я считаю, что ваша проблема связана не с вашим клиентским кодом SQL, а с вашим сервером. Стек показывает, что ваш клиент ожидает ответа. Это согласуется с тем фактом, что вы можете без проблем запустить клиент в отдельном процессе.

Итак, вам, вероятно, нужно обратить внимание на системные причины медленной работы SQL-сервера и на то, как это может быть связано с Tomcat. Мой опыт в подобных случаях обычно связан с диском, поэтому я был бы склонен проверить, выполняете ли вы подкачку из-за нехватки ОЗУ при загрузке Tomcat или страдаете от гораздо более высоких операций с диском из-за уменьшенного кеша диска. Предполагая, что вы работаете в варианте UNIX, я бы посмотрел на vmstat и iostat для рабочего и неработающего случая, чтобы устранить такие проблемы.

person Peter Brittain    schedule 15.06.2015
comment
Я уже проверил эти параметры и даже изменил параметры jvm для Tomcat. Однако по необъяснимым причинам сегодня утром производительность увеличилась, и моей проблемы больше не было. Понятия не имею почему. У меня нет полномочий над сервером, может кто-то что-то менял. - person Tim; 16.06.2015
comment
Ну что ж. По крайней мере, это работает сейчас. Кстати, я предполагал, что ваша БД и веб-сервер находятся на одном компьютере. Если нет, вы можете просто обнаружить, что БД недостаточно производительна с большими запросами для любых обычных проблем, связанных с ограничениями ресурсов. - person Peter Brittain; 16.06.2015

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

person Tim    schedule 16.06.2015

Поскольку ваш поток ожидает чтения сокета, что означает ожидание ответа от сервера базы данных, я бы:

Проверить производительность базы данных, убедиться, что ни экземпляр, ни запрос не пострадали в какой-то момент в течение дня?

Проверьте сетевые задержки между серверами Java и DB. То же, что и выше. Трассировка наверное?

person bubooal    schedule 18.06.2015
comment
Производительность БД не является проблемой — один и тот же запрос выполняется быстро вне сервлета на той же машине. - person Tim; 19.06.2015
comment
Как насчет сетевых задержек между приложениями и сервером БД? - person bubooal; 20.06.2015
comment
Я также исключил это, поскольку большинство SQL-запросов быстро выполняются в сервлете. А теперь и новые. - person Tim; 21.06.2015

Поскольку вы не поставили query, я могу дать вам сценарий, где это возможно. Если вы используете функцию в своем запросе, такую ​​​​как to_char и т. д., то индексы вашей таблицы не будут использоваться при выполнении запроса через JDBC, но будут работать нормально, если вы запустите его в консоли. Я точно не знаю, почему, но что-то с драйвером JDBC. У меня была точно такая же проблема в db2, и я решил ее, удалив использование функций.

Другой сценарий может заключаться в том, что извлекается огромное количество записей, а правильная пакетная обработка не реализована.

person ares    schedule 22.06.2015