8

It's driving me crazy. Making hibernate simple select is so slow, comparing to running that query directly via Navicat. What is more intereting. Running this query with local database is really fast, but using it remotely is really poor.

I'm doing following Hibernate native SQL query (as HQL or Criteria does not suppor left join):

List list = new ArrayList();
String queryStr = "select s.* from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null";
Query query = session.createSQLQuery( queryStr ).addEntity( SalesUnit.class );

Long start = System.currentTimeMillis();
list.addAll( query.list() );
Long stop = System.currentTimeMillis();
System.out.println( "Time: " + (stop - start) + "ms." );

Structure of Entity doesn't matter really. There's around 28k record for both SALES_UNIT and SALES_UNIT_RELATION table

The results, runned on my local JBoss with local databse, are around 30-120ms. While running on remote databasem, local JBoss (same data), results in time's between 30000-40000ms. When I'm running this query with Navicat, both local and remote calls are really fast (20-30ms).

Both local and remote database were installed same way -> Oracle Enterprise Edition 11.2.0.1.0.

WHat might be the problem of such poor performance? How can I debug it?

Read this: Simple hibernate query returning very slowly , but setting constructors didn't change anything

EDIT.

SALES_UNIT table contains some basic info abot sales unit node such as name and etc. The only association is to table SALES_UNIT_TYPE, as ManyToOne. The primary key is ID and field VALID_FROM_DTTM which is date.

SALES_UNIT_RELATION contains relation PARENT-CHILD between sales unit nodes. Consists of SALES_UNIT_PARENT_ID, SALES_UNIT_CHILD_ID and VALID_TO_DTTM/VALID_FROM_DTTM. No association with any tables. The PK here is ..PARENT_ID, ..CHILD_ID and VALID_FROM_DTTM

Community
  • 1
  • 1
kamil
  • 3,482
  • 1
  • 40
  • 64
  • 1
    It looks like a problem with your fetch size. Can you [increase it](http://stackoverflow.com/questions/3355231/whats-the-default-size-of-hibernate-jdbc-fetch-size)? Try with 100 to decrease the number of round-trips. – Vincent Malgrat Nov 09 '12 at 11:04
  • I did: `query.setFetchSize( 100 );` , but nothing changed – kamil Nov 09 '12 at 11:44
  • Do you have the same amount of data on the local and remote DB? Are the DB structures exactly the same? (just wondering if you're missing an index on the remote DB). I know that you said that the queries are fast from Navicat, but just crossing out the usual suspects. – Augusto Nov 11 '12 at 12:47
  • Yes there are the same. I did run same "init" script on both and tested once again. No indexes except PK. Additionally, there's no FK between SALES_UNIT and SALES_UNIT_RELATION – kamil Nov 11 '12 at 12:49
  • How much data is being returned by the query? Could this be a network issue? Also, I'd guess that Navicat only returns the first X rows, making it look faster than it really is. – Jon Heller Nov 11 '12 at 15:32
  • It is not a network issue. I've tested it also on my client database server with local JBoss pluged into it. The query should return just 2 elements, so it's neither problem of transporting data or size of returned data. The question is, why making query with NaviCat (or even SQLPlus) is so much faster, then Hibernate native SQL and how to debug the issue? – kamil Nov 11 '12 at 17:45
  • 1
    do you have access to v$sql, v$sql_plan on the DB? you can try to see the final sql + plan on the hibernate version to see if its not right. eg run with an indentifier `"select /* FINDME */ s.* from sales_unit..` then `select * from v$sql where sql_text like '%FINDME%'` check the consistent_gets, rows_processed etc to see if they are high also grab sql_id and child_number and use these two and query `select * from v$sql_plan where sql_id = 'x' and child_number = x` to check the plan of the hibernate version. compare to a sqlplus version (use a diff identifier to force a hard parse) – DazzaL Nov 12 '12 at 13:54
  • As I commented on the other SO question you linked (http://stackoverflow.com/questions/6609645/simple-hibernate-query-beeing-very-slow), overloaded constructors will have no affect, which you see as well. I'd be more curious to see whether you have any non-lazy associations defined on your SalesUnit entity. That is the usual cause of such a drastic time difference. Could you post that info? Also, AFAICT Navicat is not JDBC-based, so direct time comparison between a JDBC client (Hibernate) and Navicat (if not JDBC based) is a bit misleading; if that is the case, try direct JDBC access. – Steve Ebersole Nov 13 '12 at 20:06

2 Answers2

3

Thank you all for help. After long time of struggling with that issue, finally kaliatech answer helped me to debug the problem.

First of all, I've made a terrible mistake in my quesion. I wrote that:

Running this query with local database is really fast, but using it remotely is really poor.

As it is not completly true. The query which I did in Hibernate looks like the one up:

select s.* from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null

But the actual query which I did with SQL PLus or Navicat for example was:

select * from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null

Please notice that first query select starts: select s.* ... and second one is select * .... And that was the reason of such poor performance. Now both queries are completed in no time. The question is, what's the difference: performance issue: difference between select s.* vs select *

Community
  • 1
  • 1
kamil
  • 3,482
  • 1
  • 40
  • 64
  • The difference is that select s.* returns only the columns from the table that's been aliased "S", while select * will return all the columns for all the tables in the FROM clause, *INCLUDING* joined tables. – Matt Brock Nov 15 '12 at 17:44
  • The question is, why `s.*` is so slow, comparing to `*`? – kamil Nov 15 '12 at 18:03
  • Apologies, I didn't see the new question you opened regarding this issue nor the discussion it prompted. – Matt Brock Nov 15 '12 at 18:56
2

To get a definitive answer, I think more info is needed. Primarily:

  • Do you have any entity association or collection fields in the SalesUnit entity class? <-- This would be my first guess for the performance differences you are seeing in lieu of any other info.

  • Do you have the same performance issue when running the query using the same JDBC driver in a non Hibernate environment? (i.e. Using a 3rd party JDBC client like DbVisualizer).

Also,

Although it's impossible to know for sure with info in your question, I think you wanted to query for all SalesUnits that do not have a child SalesUnit. Correct? (It depends on what you are using sales_unit_relation table for.) If so, you wrote your query like this:

String queryStr = "select s.* from sales_unit s
                   left join sales_unit_relation r on 
                   (s.sales_unit_id = r.sales_unit_child_id)
                   where r.sales_unit_child_id is null";

But, I think you likely wanted something more like this:

String queryStr = "select s.* from sales_unit s
                   left join sales_unit_relation r on 
                   (s.sales_unit_id = r.sales_unit_id)
                   where r.sales_unit_child_id is null";

As is, your query is joining against the column you filter for null in the WHERE clause. If that really is what you wanted, then you could have also written it as an INNER JOIN without the WHERE clause, right?

Lastly,

I'm doing following Hibernate native SQL query (as HQL or Criteria does not support left join)

That is incorrect as stated. HQL and Criteria do not support left join only if there is not a mapped relationship between entities/tables being queried. So the assumption per your example would be that there is not a mapped entity relationship between SalesUnit and whatever entity/association the sales_unit_relation table represents. (A native query should work regardless, but if there was a mapped relationship, then one benefit to using HQL/Criteria would be that you could do a left join fetch.)

kaliatech
  • 17,579
  • 5
  • 72
  • 84
  • Thanks for answer. You were close, but it was my bad not to provide structure of both tables. Edited my question – kamil Nov 15 '12 at 13:26