Почему получение ResultSet из хранимой процедуры Oracle происходит так медленно? - PullRequest
4 голосов
/ 27 мая 2010

Мне нужно улучшить код, где хранимая процедура Oracle вызывается из Java-программы. В настоящее время код действительно очень медленный: до 8 секунд на моей машине для разработки. На той же машине, если я напрямую вызываю SQL-запрос, который выполняет примерно ту же обработку и возвращает те же данные, это занимает менее 100 мс ...

Код создает CallableStatement, регистрирует один из выходных параметров как курсор Oracle, а затем извлекает курсор с помощью метода getObject оператора и анализирует его в ResultSet:

cstmt = conn.prepareCall("{ call PKG_ESPECEW.P_ListEspece( ?, ?, ?, ?, ?, ? ) }");
cstmt.registerOutParameter(4, oracle.jdbc.OracleTypes.CURSOR);
[...]
cstmt.executeQuery();
rs = (ResultSet)cstmt.getObject(4);
rs.setFetchSize(1000); //supposed to help ?

options = new HashMap<String, String>(1000);
rs.next() //added that to measure exactly the length of the first call

while(rs.next()) {
    [...]
}

Я добавил несколько временных меток в код, чтобы узнать, какая часть занимает так много времени. Результат: первый вызов rs.next() занимает несколько секунд. Наборы результатов в среднем, от 10 до нескольких тысяч строк. Как я уже говорил, обработка похожих наборов результатов, поступающих из обычного PreparedStatement, занимает 10-100 мс в зависимости от размера.

Что-то не так с кодом? Как мне улучшить это? Я сделаю прямой SQL там, где это критично, если у меня нет другого решения, но я бы предпочел решение, которое позволит мне не переписывать все процедуры!

Вот определение хранимой процедуры:

PROCEDURE P_ListEspece(P_CLT_ID IN ESPECE.ESP_CLT_ID%TYPE,     -- Langue de l'utilisateur
                        P_ESP_GROUP_CODE IN ESPECE.ESP_CODE%TYPE,-- Code du groupe ou NULL
                        P_Filter IN VARCHAR2,                   -- Filtre de la requête
                        P_Cursor OUT L_CURSOR_TYPE,             -- Curseur
                        P_RecordCount OUT NUMBER,               -- Nombre d'enregistrement retourne
                        P_ReturnStatus OUT NUMBER);              -- Code d'erreur

Ответы [ 4 ]

3 голосов
/ 28 мая 2010

"Я думал, что процедура была выполнена, затем ее результат сохраняется в памяти сервера Oracle и, наконец, передается обратно клиенту (приложение Java) через курсор и набор результатов и JDBC"

Это неправильно. То, что оракул возвращает в виде курсора, является в основном указателем на запрос (все готово с любыми переменными связывания). Он не материализовал набор результатов в памяти. Это может быть массивный набор результатов из миллионов / миллиардов строк.

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

1 голос
/ 27 мая 2010

Сколько времени занимает выполнение процедуры вне Java? Проверьте с помощью такого сценария в SQL * Plus:

var ref refcursor
var cnt number
var status number
exec p_listespece (xx, yy, zz, :ref, :cnt, :status);--replace with actual values
print :ref

Если это занимает более 10-100 мс, ваша проблема может возникнуть из-за хранимой процедуры.

1 голос
/ 27 мая 2010

Очевидно, что хранимая процедура выполняет некоторое преобразование / массивацию данных вперед и назад (например, int <-> varchar). Известно, что в случае больших таблиц это занимает много времени. Убедитесь, что вы указали правильные типы данных в аргументах SP и задаете правильные типы данных в CallableStatement.

0 голосов
/ 21 февраля 2018

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

вот фрагмент:

`

String sql = "call MyStored(?,?,?,?)";
CallableStatement st = Conn.prepareCall(sql);
st.setInt(1, 10);
st.setInt(2, 20);
st.setInt(3, 30);
st.registerOutParameter(4, OracleTypes.VARCHAR);

st.execute();

String query = (String) st.getObject(4);
Statement stmt = Conn.createStatement();
rs = stmt.executeQuery(query);
[...]
//work with resultset
[...]
stmt.close();
stmt = null;

`

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...