views:

228

answers:

1

Some of the queries we run have 100'000+ results and it takes forever to load them and then send them to the client. So I'm using ScrollableResults to have a paged results feature. But we're topping at roughly 50k results (never exactly the same amount of results).

I'm on an Oracle9i database, using the Oracle 10 drivers and Hibernate is configured to use the Oracle9 dialect. I tried with the latest JDBC driver (ojdbc6.jar) and the problem was reproduced.

We also followed some advice and added an ordering clause, but the problem was reproduced.

Here is a code snippet that illustrates what we do:

final int pageSize = 50;
Criteria crit = sess.createCriteria(ABC.class);
crit.add(Restrictions.eq("property", value));
crit.setFetchSize(pageSize);
crit.addOrder(Order.asc("property"));
ScrollableResults sr = crit.scroll();
...
...
ArrayList page = new ArrayList(pageSize);
do{
  for (Object entry : page)
    sess.evict(entry); //to avoid having our memory just explode out of proportion
  page.clear();
  for (int i =0 ; i < pageSize && ! metLastRow;  i++){
    if (sr.next())
      page.add(sr.get(0));
    else 
      metLastRow = true;
  }
  metLastRow = metLastRow?metLastRow:sr.isLast();

  sendToClient(page);
}while(!metLastRow);

So, why is it that I get the result set to tell me its at the end when it should be having so much more results?

+1  A: 

Your code snippet is missing important pieces, like the definitions of resultSet and page. But I wonder anyway, shouldn't the line

if (resultSet.next())

be rather

if (sr.next())

?

As a side note, AFAIK cleaning up superfluous objects from the persistence context could be achieved simply by calling

session.flush();
session.clear();

instead of looping through the collection of object to evict each separately. (Of course, this requires that the query is executed in its own independent session.)

Update: OK, next round of guesses :-)

Can you actually check what rows are sent to the client and compare that against the result of the equivalent SQL query directly against the DB? It would be good to know whether this code retrieves (and sends to the client all rows up to a certain limit, or only some rows (like every 2nd) from the whole resultset, or ... that could shed some light on the root cause.

Another thing you could try is

crit.setFirstResults(0).setMaxResults(200000);
Péter Török
You are right about the first part. I have improved the code snippet. This is stuff taken from two classes that I'm merging together to make it more readable.
mlaverd
You are right also about the `session.flush();` part. The thing is, since the code is part of an utility class, I want to make sure that there wouldn't be any side-effects in other parts of the code. Calling `session.evict()` looked a whole lot safer.
mlaverd
I traced the SQL statement generated by Hibernate and ran it separately, and I was able to retrieve all the 100'000+ rows
mlaverd
@mlaverd Fine, now could you do the comparison of results as I suggested above?
Péter Török
I ran the same query Hibernate executes, and it fetches all 100'000+ results. I compared the results and there is nothing skipped either.
mlaverd
`crit.setFirstResults(0).setMaxResults(200000);` didn't help. Same result.
mlaverd
I changed `crit.scroll()` to `crit.scroll(ScrollMode.FORWARD_ONLY)`. Now, instead of having a weird situation where results are no longer coming, I'm getting a socket closed exception. Is there a way to work around that?
mlaverd
@mlaverd That sounds weird... could it be that the underlying network connection was closed too early for some reason (timeout)? Approximately how long the above code takes to run?
Péter Török
Using a page size of 150, roughly half an hour. Then the socket closed exception happens.
mlaverd
@mlaverd This reinforces my theory that the network connection got closed somehow. However, I am not an expert in socket programming, so I can't offer any advice on that. You could try updating your question with these new findings and retagging (possibly renaming) it to attract socket gurus...
Péter Török