-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: Subject: Governed Search Strategy - SQL Tuning
PostPosted: Fri Dec 10, 2004 5:13 pm 
Regular
Regular

Joined: Tue Nov 30, 2004 4:23 pm
Posts: 62
There is a specific reason that I have been asking about things like QueryTranslator and setMaxResults. I am working on a project that abstracts out much of the persistence layer functionality from developers, except for the creation of DAOs, BOs, and HQL statements. Developers send in an HQL query, and we are looking to do two types of queries behind the scenes. Some of our data tables will contain 5+ million records, and so we had to define our search strategies into three categories. One of the categories has been coined a goverened search strategy. This strategy is based on the suggestions of Dan Tow in SQL Tuning (page 256):

Quote:
    1. Determine the maximum-length list you want to return (1000 for us)
    2. In the call, request one more row than the max (1001)
    3. Query execution plane is robust without prehash, sort, or storing whole large rowsets
    4. Request that the query result from the database be unsorted
    5. Sort the result as needed in the application layer
    6. Cancel the query and return an error that suggests a more selective search


So what we are trying to accomplish is two queries from one initial query. The user will send us an HQL statement and we want to test the governed portion before we submit the query. As far as the setMaxResults goes, Hibernate successfully does its job of creating a DB2 statement of "fetch first n rows". The only problem with this (which is DB2 not Hibernate) is this may be too much work just to check if the soon to be submitted query is going to request too many rows. So what we need to do is insure that the indexes are being queried against and that the query can acquire the necessary row count without hitting the data tables.

The following was done on a sister project in native jdbc, which worked with the suggestions made in SQL Tuning and created a significant performance benefit between these two types of queries:

General Way
Code:
java.sql.Connection con = JDBCConnectionFactory.getConnection();
java.sql.Statement statement = con.createStatement();
String countSQL = "Select Count(*) From user u, user_account ua " +
"Where u.id = ua.id For Read Only";
java.sql.ResultSet rs = statement.executeQuery(countSQL);
int count = 0;
// Now select the actual count.
if (rs.next() == true) {
count = rs.getInt(1);
System.out.println("Matches found: " + count);
}
rs.close();
statement.close();
con.close();

Problems
- This query may need to hit data tables
- count(*) requires a complete result set before actually completing
- This also means that count(*) will require a temporary table to be created

Faster Way
Code:
long rowLimit = 1000;
java.sql.Connection con = JDBCConnectionFactory.getConnection();
java.sql.Statement statement = con.createStatement();
String countSQL = "Select 1 From user u, user_account ua " +
"Where u.id = ua.id For Read Only";
java.sql.ResultSet rs = statement.executeQuery(countSQL);
int rowCount = 0;
while (rowCount <= rowLimit && rs.next() == true) {
rowCount++;
}
if (rowCount > rowLimit) {
System.out.println("Row limit exceeded!");
} else {
System.out.println("Matches found:" + rowCount);
}
rs.close();
statement.close();
con.close();

Benefits
- Select 1 (constant) does not require the creation of a temporary table
- Because of DB2's fast initial results, the code can begin to receive results and begin processing a row count before the actual query completes, therefore allowing the query to be intercepted once it has passed the allowable row limit.

So the faster option requires the creation of an SQL statment with constants, which I don't believe is a capability in Hibernate's HQL at this time. This is why we have the need to take the developer's original HQL query and extract the SQL from the HQL statement. And to even further add performance and processing speed, we want to send in an HQL statement and only transform particular statements into SQL. So in our case, we only need to transform the from and where clauses into SQL, and ignoring possible performance time to transform the select statement. Then we can utilize just the from and where clause to construct the constant query to check for row count on the result, then submitting the original HQL query if the results of the constant query are less than 1001.

I am really looking for Hibernate team feedback to provide any potential suggestions?

Thanks,

-jay


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 10, 2004 6:18 pm 
Expert
Expert

Joined: Sat Jun 12, 2004 4:49 pm
Posts: 915
Jay,
You can use hibernate ScrollableResults and call scr.first - I am sure that hibernate will the best for You - every your example work better with scrollable ResultSet (from jdbc) if database do scrolling correct - I don't know DB2 enough, but I think that DB2 do correct scrolling

performance penal between 'select 1' and 'select id' are minor, I'm sure - it is populate only one column and it can't be important - try from jdbc for only one row except while loop create only
scrollable resultset and call rs.last() - it can be quicker

regards
Peco


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 10, 2004 7:13 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
I *think* what i'm seeing is that you can use scrollabe resultset (as someone else suggested) to decide what will "happen" - so that is "possible now".


The other issue with "getting the sql going to be executed from a Query.class" is "harder" because one HQL query can actually be multiple sql strings - and as it is now the QueryImpl class don't even know these ...that is handled by SessionImp together with some QueryTranslators.

...don't know if one could provide a clean way of providing hooks for this at the moment.

But i will suggest you to try and come up with a mechanism that could help you and suggest it as an improvement to Hibernate 3 in the jira (and make a link to this posting too)

No promises though ;)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 10, 2004 9:40 pm 
Regular
Regular

Joined: Tue Nov 30, 2004 4:23 pm
Posts: 62
I know you mentioned some classes in your response, do you have or can recommend a class/interface that I can utilize as a path into Hibernate to accomplish what I am looking for. I thought QueryTranslator would be the solution, but Gavin mentioned that it is an "Internal Implementation". The reason I am in definite need of a quality solution, is that I have architects that have already accomplished this through Java and JDBC. Also, there are strict requirements because of the record sizes that will be incurred in production and the amount of queries that will be performed daily will be extensively high.

Thanks,

-jay


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 11, 2004 3:05 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
look at Query and what it implementation QueryImpl calls when doing a list. Follow that and you will see it actually calls N QuerytTranslators resulting in possible multiple queries to be executed.

Maybe there could be some kind of callback, but i'm afraid it will give more troubles than solutions.

Is this "query-checking" something that you want on ALL queries by default ?

And the goal is just to do a "probe" of the query to see if it is ok to actually execute the correct sql query, correct ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 11, 2004 1:01 pm 
Regular
Regular

Joined: Tue Nov 30, 2004 4:23 pm
Posts: 62
We have a few search strategies, but this particular strategy allows developers to enter any type of HQL statements regardless of the amount of joins and whether they hit data tables or indexes. So the issue here is the fastest performance for retrieving whether the potential query could retrieve too many rows. The best solution would be the ability to use a constant in the select statement. Since this can't be accomplished with Hibernate, then the next best option is for us to write the SQL statement ourselves. But since HQL is not directly SQL, we need to intercept the translation between HQL and SQL or we need to submit an HQL statement and retrieve specific SQL clauses from that statement. Like I said, a sister project was able to accomplish this necessary functionality with Java and JDBC. So I need the easiest possible hooks into retrieving this information, or may have to try and architect an HQL to SQL parser to retrieve this necessary information. We don't want the developers to have to submit and SQL statement for doing a select constant and then the HQL statement and submitting it. We would really like to solve testing the governed and the submission of the HQL with one statement.

-jay


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 11, 2004 1:08 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
may i ask why you don't just uses createSQLQuery ?

And is this something you put in a production system ? That you pre-execute the query and then maybe modify the sql to execute it again ?

regarding supporting this stuff (which sounds really something which only should be done through development) would it be enough to e.g. via an event or callback on the session to receive the sql string before it's being executed ? (like String aboutToExecute(String sql)) ..

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 13, 2004 11:28 am 
Regular
Regular

Joined: Tue Nov 30, 2004 4:23 pm
Posts: 62
We are using version 2.1.6, is there a class with the method createSQLQuery in this version.

And yes, this is something that we will do in production. Every search that requires the governed strategy will actually run to queries. One to test the governed and one to submit the query. We only modify the first test, and not the actual submission of the second query.

As far as callbacks, that is definitely something we could look at.

-jay


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 13, 2004 2:19 pm 
Newbie

Joined: Mon Dec 13, 2004 1:54 pm
Posts: 1
Not to interrupt what you are asking, but I ran along the sames lines of issues with our query approach. Many of the ORM products have a sort of proprietary solution for the interim query language that is translated into SQL and the additional code that is involved. EJB has its EJB-QL and so Hibernate has its proprietary HQL. You could ask all your developers to write their statements directly using SQL instead of HQL, that way you can remove the issues of the HQL transformation and performance of that transformation. I looked into Cayenne also, but it seems to have the same issues, either use specific language/objects to transform data into SQL (specific to the database type) or write straight SQL. There is a new little ORM tool called Mr. Persister that does not use a proprietary language, it only uses straight SQL. It does not provide all the functionality that Hibernate does, but you would not have to spin your wheels on the complication of HQL -> SQL.

just a thought...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 13, 2004 2:42 pm 
Expert
Expert

Joined: Sat Jun 12, 2004 4:49 pm
Posts: 915
kludgycode,
hql is main power of hibernate - You have to have preformance down when you work more jobs - for instance, hibernate populate beans properties after loading result set and it is performance decrease, but hibernate do it for us - if you don't want it you can use pure jdbc always

regards


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 16, 2004 1:47 pm 
Regular
Regular

Joined: Tue Nov 30, 2004 4:23 pm
Posts: 62
Is there a way to run an HQL statement through the architecture without it submitting the SQL request? I am going to download the Hibernate source and create a hook to extract the SQL statement. I will submit an HQL statement and extract the SQL statement, but I don't want the statement to process against the database. Can I do this?

Thanks,

jay


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 16, 2004 4:27 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
in hibernate3 is at least somewhat accessible via the new querytranslator (but it is still a nonpublic API)

Take a look at assertTranslation usage in the new hql test package in h3.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 16, 2004 6:32 pm 
Pro
Pro

Joined: Tue Aug 26, 2003 8:07 pm
Posts: 229
Location: Brisbane, Australia
If you've given up trying to get a hook from Hibernate to pre-process the HQL, and now you're just interested in transforming the SQL that Hibernate actually issues, what about writing a JDBC Driver wrapper?

Kind of like what P6Spy does, but instead of logging the SQL then forwarding it to the real driver, you'd transform the SQL then forward it to the real driver.

Just a thought.

_________________
Cheers,
Shorn.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.