Patryk Sosiński

Patryk Sosiński Architekt,
Specjalista GIS,
Programista

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Cześć

Mam taki problem. Poprzez jdbc próbuje wykonać zapytanie np:

select * from tabela;

tabela ma powiedzmy 20 mln wierszy, do tego wiersze zawierają kolumny powiedzmy varchar(4000).

Przy wykonywaniu tego zapytania dostaje błąd:
ORA-02395: exceeded call limit on IO usage
Zmiana parametru nie wchodzi w grę, nie mam praw administratora.

Czy ktoś zna sposób na pozbycie się tego błędu. Czy można w jdbc wymusić aby pobierał tylko paczki danych?

konto usunięte

Temat: jdbc ORA-02395: exceeded call limit on IO usage

select * from tabela
where ROWNUM < n;

To jest tylko zalążek pomyślu.

Powstaje pytanie co z następnymi wierszami. Polecam zajrzeć do tego wątku:

http://www.goldenline.pl/forum/oracle/599786/?hl=rownum

Zostało tu omówionych kilka ciekawych rozwiązań.Adam Michalski edytował(a) ten post dnia 13.11.09 o godzinie 21:27
Patryk Sosiński

Patryk Sosiński Architekt,
Specjalista GIS,
Programista

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Ale ja muszę pobrać całą tabelę.

konto usunięte

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Na raz? A po co?
Patryk Sosiński

Patryk Sosiński Architekt,
Specjalista GIS,
Programista

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Muszę skopiować całą tabelę do pliku (odpowiednio formatując).
Nie chce używać gotowych narzędzi.
Nie musi być na raz, może być kopiowanie paczkami.

Problem w tym, że każda operacja np sortowania po tabeli znacznie spowalnia całe zapytanie.

Szukam rozwiązania, które pozwoli mi pobrać całą tabelę paczkami.

konto usunięte

Temat: jdbc ORA-02395: exceeded call limit on IO usage

To przejrzyj wątek, który Ci podałem. Jest tam podanych kilka rozwiązań wraz z analizą ich efektywności. Jeśli nie da się pobrać na raz, to musisz pobierać w paczkach. Nie masz wyjścia, ponieważ, jak sam napisałeś, nie możesz ingerować w ustawienia samego Oracla.
Patryk Sosiński

Patryk Sosiński Architekt,
Specjalista GIS,
Programista

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Dzięki za linka!
Szkoda tylko, że cały ten wątek opiera się na posortowanym kluczu głównym ale chyba nie ma innego rozwiązania.

Nie ma przecież gwarancji, że Oracle zwróci dane w tej samej kolejności.Patryk Sosiński edytował(a) ten post dnia 13.11.09 o godzinie 21:57
Irek Słonina

Irek Słonina programowanie, bazy
danych i linuksy

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Patryk Sosiński:
Dzięki za linka!
Szkoda tylko, że cały ten wątek opiera się na posortowanym kluczu głównym ale chyba nie ma innego rozwiązania.

Nie ma przecież gwarancji, że Oracle zwróci dane w tej samej kolejności.Patryk Sosiński edytował(a) ten post dnia 13.11.09 o godzinie 21:57


jeśli nie masz posortowanego, unikalnego klucza głównego to użyj rowid
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Patryk Sosiński:
Muszę skopiować całą tabelę do pliku (odpowiednio formatując).

Skoro chcesz przelecieć całą sporą tabelę to w JDBC użyj scrollable results.

Wygooglałem pierwszą z brzegu stronę na ten temat:
http://java.sun.com/developer/onlineTraining/Programmi... ---->

"JDBC 2.0 introduces scrollable results sets..."

Pozdrowienia,
Adam Woźniak
Wojciech Nowak

Wojciech Nowak Konsultant Systemów
Bankowych | Analityk
Systemowy

Temat: jdbc ORA-02395: exceeded call limit on IO usage

witam,

a kto robi select gwiazdka po tabeli z 20 mln rekordów ?
jeżeli to ma być cała tablica do pliku to zrób skrypt sh (jeśli to unix) z poleceniem eksportu do odpowiedniego pliku a skrypt wywołaj z aplikacji.

Ewentualnie można wykorzystać pakiet utl_file i przygotować procedurę z eksportem.

pzdr.
Sebastian Kolski

Sebastian Kolski programista/DBA

Temat: jdbc ORA-02395: exceeded call limit on IO usage

ORA 2395 mówi o przekroczeniu limitu LOGICAL_READS_PER_CALL z profilu.

Z SQL Lang Ref
"LOGICAL_READS_PER_CALL Specify the permitted number of data blocks read for a call to process a SQL statement (a parse, execute, or fetch)."

z Metalink doc ID 872133.1
"To explain further, by way of example, suppose we have set arraysize to 500 in sqlplus (SET ARRAYSIZE=500) to limit each fetch to 500 rows. Then the maximum value that LOGICAL_READS_PER_CALL will ever get to (for a select * from tab1) is 500/(number of rows of tab1 that fit on a block). So if there are 10 rows on each block, then the maximum LOGICAL_READS_PER_CALL would reach would be 50 as each 500 rows would instigate a new fetch, i.e. a new call, and reset the count. In the case of a select count(*), only one row is returned so all the gets are under one call, hence the limit would be exceeded."

Spróbuj zmniejszyć fetch size (setFetchSize na Statement lub ResultSet). Co prawda zabije to pewnie wydajność, ale jeśli masz to zrobić tylko raz...

Rozwiązania z ROWNUM lu RANK raczej nie pójdą bo zawierają chyba dostęp do całej tabelki w jednym call'u.

Scrollable results w takim przypadku to chyba też kiepski pomysł.
Z "Oracle® Database JDBC Developer's Guide, 11g Release 2 (11.2)" Chapter 17

"Oracle JDBC Implementation for Result Set Scrollability

Because the underlying server does not support scrollable cursors, Oracle JDBC must implement scrollability in a separate layer.

It is important to be aware that this is accomplished by using a client-side memory cache to store rows of a scrollable result set.

Important:
Because all rows of any scrollable result set are stored in the client-side cache, a situation, where the result set contains many rows, many columns, or very large columns, might cause the client-side Java Virtual Machine (JVM) to fail. Do not specify scrollability for a large result set."

Jeśli masz dostęp do utl_file to pewnie wystarczy jeden wieczór grzebania po blogach z oracle security aby z eskalować to do sysdba i poprawić sobie limit :p

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Patryk Sosiński:
Czy można w jdbc wymusić aby pobierał tylko paczki danych?

Czy błąd występuje przy pobieraniu po 1 rekordzie?
tzn. stosujesz konstrukcję typu:
rset = stmt.executeQuery( sql);
while (rset.next()) {
System.out.println( rset.getObject( "POLE1") ;
}

czy próbujesz pobrać wiekszą ilość rekordów na raz ?
Patryk Sosiński

Patryk Sosiński Architekt,
Specjalista GIS,
Programista

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Piotr Wolański:

Czy błąd występuje przy pobieraniu po 1 rekordzie?
tzn. stosujesz konstrukcję typu:
rset = stmt.executeQuery( sql);
while (rset.next()) {
System.out.println( rset.getObject( "POLE1") ;
}

czy próbujesz pobrać wiekszą ilość rekordów na raz ?

wywala się stmt.executeQuery();
Sebastian Kolski:
Spróbuj zmniejszyć fetch size (setFetchSize na Statement lub
ResultSet). Co prawda zabije to pewnie wydajność, ale jeśli masz > to zrobić tylko raz...

Już wcześniej próbowałem używać tego parametru, jednak dodanie go z różnymi parametrami nie wpływa w jakikolwiek sposób na działanie aplikacji. Tak jakby setFetchSize() wogóle nie działało, albo ja nie wiem jak go użyć. Ogólnie nie przechodzi stmt.executeQuery() tak więc i tak nie ma co fetchować.

Poradziłem sobie w trochę inny sposób. Pobieram max(id), min(id) z tabeli a następnie co stmt.executeQuery() wykonuje dla id between min(id) a min(id) + 1mln. i tak dopóki nie dojdzie do max(id).
Nie jest to optymalne gdyż jeśli id jest rostrzelone czasami executeQuery() nie zwróci wynikow. Nie testowałem jeszcze rozwiązania z użyciem rownum ale wydaje mi się, że tam za każdym razem trzeba pobrać większa paczkę danych i potem ograniczać rownumem, więc i tak w pewnym momencie się wywali.

Szkoda, że nie ma czegoś takiego jak rownum between x and yPatryk Sosiński edytował(a) ten post dnia 15.11.09 o godzinie 15:47
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Sebastian Kolski:
[..]
Scrollable results w takim przypadku to chyba też kiepski pomysł.
Z "Oracle® Database JDBC Developer's Guide, 11g Release 2 (11.2)" Chapter 17

"Oracle JDBC Implementation for Result Set Scrollability

Because the underlying server does not support scrollable cursors, Oracle JDBC must implement scrollability in a separate layer.

It is important to be aware that this is accomplished by using a client-side memory cache to store rows of a scrollable result set.

Important:
Because all rows of any scrollable result set are stored in the client-side cache, a situation, where the result set contains many rows, many columns, or very large columns, might cause the client-side Java Virtual Machine (JVM) to fail. Do not specify scrollability for a large result set."

Hmmm, ciekawe.

Mówiąc szczerze, to Scrollable results używam w Hibernate, a nie w czystym JDBC i może dlatego, nie znałem tego ograniczenia Oraclowego sterownika JDBC.

Scrollable results w Hibernate i na bazie Oracle działają mi bardzo dobrze. Gdyby wyniki moich scrolli były trzymane po stronie clienta (czyli mojej aplikacji), to mojej aplikacji kończyłaby się pamięć i by się przewracała. Zatem, wnioskuję/zgaduję, że Hibernate w przypadku Oracle, jakoś inaczej realizuje Scrollable results niż przy pomocy tych ograniczonych Oraclowych mechanizmów JDBC, o których wkleiłeś informacje powyżej.

W dukumentacji do Hibernate napisane jest:
http://docs.jboss.org/hibernate/stable/core/reference/...

If your JDBC driver supports scrollable ResultSets, the Query interface can be used to obtain a ScrollableResults object that allows flexible navigation of the query results.
Note that an open database connection and cursor is required for this functionality. Use setMaxResult()/setFirstResult() if you need offline pagination functionality.


Pozdrawiam,
Adam Woźniak
Sebastian Kolski

Sebastian Kolski programista/DBA

Temat: jdbc ORA-02395: exceeded call limit on IO usage

Patryk Sosiński:
Sebastian Kolski:
Spróbuj zmniejszyć fetch size (setFetchSize na Statement lub
ResultSet). Co prawda zabije to pewnie wydajność, ale jeśli masz > to zrobić tylko raz...

Już wcześniej próbowałem używać tego parametru, jednak dodanie go z różnymi parametrami nie wpływa w jakikolwiek sposób na działanie aplikacji. Tak jakby setFetchSize() wogóle nie działało, albo ja nie wiem jak go użyć. Ogólnie nie przechodzi stmt.executeQuery() tak więc i tak nie ma co fetchować.

Poradziłem sobie w trochę inny sposób. Pobieram max(id), min(id) z tabeli a następnie co stmt.executeQuery() wykonuje dla id between min(id) a min(id) + 1mln. i tak dopóki nie dojdzie do max(id).
Nie jest to optymalne gdyż jeśli id jest rostrzelone czasami executeQuery() nie zwróci wynikow. Nie testowałem jeszcze rozwiązania z użyciem rownum ale wydaje mi się, że tam za każdym razem trzeba pobrać większa paczkę danych i potem ograniczać rownumem, więc i tak w pewnym momencie się wywali.

Szkoda, że nie ma czegoś takiego jak rownum between x and yPatryk Sosiński edytował(a) ten post dnia 15.11.09 o godzinie 15:47

Jeśli wywala ci się executeQuery() to znaczy, że albo masz query który ma w sobie dostęp do całej tabelki (np ma sorta), albo pierwszy fetch od razu przekracza limit (executeQuery() robi od razu pierwszego fetcha, zanim można ustawić fetch size na result set). Jeżeli, to nie query (sprawdź uruchamiając np w sqlplusie) to musisz ustawiać fetch size na poziomie statement.

Test case:
tabelka ~22m rekordów
limit w profilu 100 LOGICAL_READS_PER_CALL
program wykonujący query przekazane w pierwszym parametrze i ustawiający fetch size z drugiego parametru

ustawienia bazy

SQL> connect sk_test
Enter password:
Connected.
SQL> select count(*) from test;

COUNT(*)
----------
22382208

SQL> select limit from dba_profiles where profile = 'TEST' and RESOURCE_NAME='LOGICAL_READS_PER_CALL';

LIMIT
----------------------------------------
100

SQL> alter user sk_test profile test;

User altered.

SQL> connect sk_test
Enter password:
Connected.
SQL> select count(*) from test;
select count(*) from test
*
ERROR at line 1:
ORA-02395: exceeded call limit on IO usage


program

public static void main(String[] args) throws SQLException {
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@xxxx:1521:xxxx", "sk_test", "xxxx");
try {
String stmt = args[0];
PreparedStatement pstmt = conn.prepareStatement(stmt);
try {
pstmt.setFetchSize(Integer.valueOf(args[1]));
ResultSet rs = pstmt.executeQuery();
try {
int i = 0;
while (rs.next()) {
i++;
if (i % 1000 == 0) {
System.out.println(i);
}
}
} finally {
rs.close();
}
} finally {
pstmt.close();
}
} finally {
conn.close();
}
}


test - select *, fetch size 10

$ /usr/java/latest/bin/java -jar JDBCTest.jar "SELECT * FROM TEST" 10
1000
2000
3000
4000
5000
6000
7000
8000
^C


test - select *, fetch size 10000

$ /usr/java/latest/bin/java -jar JDBCTest.jar "SELECT * FROM TEST" 10000
Exception in thread "main" java.sql.SQLException: ORA-02395: exceeded call limit on IO usage

at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:1034)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:791)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:866)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1186)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3431)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1491)
at org.skolski.jdbctest.Main.main(Main.java:19)


test - select * z order by, fetch size 10

$ /usr/java/latest/bin/java -jar JDBCTest.jar "SELECT * FROM TEST ORDER BY CREATED_T" 10
Exception in thread "main" java.sql.SQLException: ORA-02395: exceeded call limit on IO usage

at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:1034)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:791)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:866)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1186)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3431)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1491)
at org.skolski.jdbctest.Main.main(Main.java:19)



Wyślij zaproszenie do