Снижение производительности в CallableStatement

У меня есть хранимая процедура в Oracle 11g, которую я вызываю из программы на Java, используя тонкий драйвер базы данных Oracle и CallableStatement. Эта хранимая процедура вызывается тысячи раз в цикле по одному и тому же соединению.

Вызов callableStatement.execute() возвращается через ‹ 200 мс для первых 10-20 вызовов, однако производительность со временем начинает ухудшаться. После 200 вызовов callableStatement.execute() теперь занимает 600 мс и продолжает ухудшаться.

Если я периодически закрываю соединение, время выполнения возвращается к нормальному диапазону ‹ 200 мс. Явно что-то неправильно кэшируется в соединении JDBC, хотя в документации указано, что CallableStatements не кэшируются.

Выполнение той же хранимой процедуры с использованием драйвера Oracle OCI в программе на языке C не показывает снижения производительности и постоянно возвращает результат в течение ‹ 200 мс.

Кто-нибудь заметил это поведение или есть какие-либо мысли об обходном пути для Java?

Редактировать: это часть кода, которая запускается много раз; Соединение является общим, CallableStatement создается в каждом цикле. Нет улучшений, если CallableStatement кэшируется.

   oracle_conn_time = System.currentTimeMillis();
   OracleConnection oracle_conn = (OracleConnection) conn.getMetaData().getConnection();
   oracle_conn.setStatementCacheSize(1);
   oracle_conn_time = System.currentTimeMillis() - oracle_conn_time;

   list_time = System.currentTimeMillis();
   var_args= oracle_conn.createARRAY("ARG_LIST", args.toArray());
   list_time = System.currentTimeMillis() - list_time;

   sql       = "{? = call perform_work(?,?,?,?)}";

prepare_time = System.currentTimeMillis();
ocs = (OracleCallableStatement) oracle_conn.prepareCall(sql);
prepare_time = System.currentTimeMillis() - prepare_time;

bind_time = System.currentTimeMillis();
    ocs.registerOutParameter(1, OracleTypes.ARRAY, "RESPONSEOBJ");

    ocs.setInt(  2, 77);
    ocs.setInt(  3, 123456);
    ocs.setArray(4, var_args);
    ocs.setInt(  5, 123456789);
    bind_time = System.currentTimeMillis() - bind_time;

//execute_time is the only timer that shows degradation
execute_time = System.currentTimeMillis();
    ocs.execute();
execute_time = System.currentTimeMillis() - execute_time;

results_time = System.currentTimeMillis();
    Array return_objs = ocs.getArray(1);
results_time = System.currentTimeMillis() - results_time;

oracle_time = System.currentTimeMillis() - oracle_time;
    parse_time = System.currentTimeMillis();

    Clob[] clobs = (Clob[]) return_objs.getArray();

    return_objs.free();

//Removed clob management code

parse_time = System.currentTimeMillis() - parse_time;

person Samhain    schedule 06.12.2013    source источник
comment
Можете ли вы опубликовать свой код? Проверьте следующую ссылку, мне кажется, что у меня похожий вопрос /вопросы/8747937/   -  person Mani    schedule 07.12.2013
comment
Что произойдет, если вы будете совершать каждые 10 вызовов?   -  person Mark Rotteveel    schedule 07.12.2013
comment
@MarkRotteveel Добавление фиксации не помогает. Добавление кода выше   -  person Samhain    schedule 09.12.2013


Ответы (1)


Когда хранимая процедура возвращала массив Clob, код освобождал только массив напрямую, а не базовые объекты Clob.

Добавление вызова free к объекту Clob устранило снижение производительности.

Я предполагаю, что когда объект Clob очищается от мусора, free по сути вызывается в finalize, но я подозреваю, что объект Oracle Connection содержит ссылку на любые используемые объекты Clob, тем самым предотвращая его сборку мусора. Глупый промах с моей стороны, но, надеюсь, это поможет кому-то не попасть впросак в будущем.

Array return_objs = ocs.getArray(1);

Clob[] clobs = (Clob[]) return_objs.getArray();

return_objs.free();

for(int i = 0; i < clobs.length; i++ )
{
    //Utilize clob

    clobs[i].free();
}
person Samhain    schedule 09.12.2013