Skip to content

SubQuery Join with "OR" statement #2373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
DaveLaa opened this issue May 7, 2020 · 2 comments
Closed

SubQuery Join with "OR" statement #2373

DaveLaa opened this issue May 7, 2020 · 2 comments

Comments

@DaveLaa
Copy link

DaveLaa commented May 7, 2020

I have a Problem with a sql statement NHibernate generates when it comes to subquery joins. I have 2 tables, TableA and TabbleB, that are mapped to classes but without a mapped connection (OneToMeny/ManyToOne). These tables are actually complex views containing a huge amount of data each (several milions of rows).

In my code it is neccessary to build complex queries in both tables and connect them to one result. The conditions of those queries are different in each occurence in code but I managed to build them all in one big query class. That works perfectly and is very intuitive and readable code.

I use a query like this simplified one to get the results of my requests:
var sub = Dao.Session.Query().Where( ...condition... );
var result = Dao.Session.Query().Where( p=> sub.Any( q=> q.RefAId = p.Id ) && ... ).ToArray();
Of course both query trees of TableA and TableB are attached to complex where conditions but these aren't neccessary here.

The sql statement genereted by NHibernate looks about like this:
SELECT * FROM TableA a WHERE EXISTS( SELECT Id FROM TableB b WHERE (a.Id = b.RefAId OR a.Id IS NULL AND b.RefAId IS NULL) AND ... ) ...
This is technically correct and works fine but is very slow because of the "...OR a.Id IS NULL AND b.RefAId IS NULL" part. The Oracle optimizer doesn't like "OR" whithin join conditions and the "... IS NULL" statements lead to full table scans because nulls are not content of any index. I have a runtime difference of 30Minutes with the OR part and 0,05 seconds without.
I mapped both properties of the join as NOT NULL (TableA.Id is the Id column) but still NHibernate generats the "OR" part.
If I add " && q.RefAId != null" in the join condition of the request it gets better because then the "NOT NULL" signals oracle to use a different execution plan and the runtime goes down to several seconds, still too long.

Only way to get rid of the "OR" part is to make a mapped connection between the tables and rewrite my query class to statements like this:
var result = Dao.Session.Query().Where( p=> p.TableBRefs.Any( q=> ...condition... ) && ... ).ToArray();
Then the sql generated looks like this:
SELECT * FROM TableA a WHERE EXISTS( SELECT Id FROM TableB b WHERE a.Id = b.RefAId AND ... ) ...
This statement ist exactly the same as before but without the "OR" part and now it ist fast (0,05 secs).
Only Problem I have is that my query class would be very ugly, containing a lot of copied parts to handle the different combinations of conditions of my complex requests. This would blow up my code unneccessarily...

Is there a way that NHibernate realizes when the "OR" part is usefull and when it can be skiped (for exaple if both columns are NOT NULL mapped)? That would be a great help to speedup my project.

@bahusoid
Copy link
Member

bahusoid commented May 7, 2020

Duplicate of #1860

@bahusoid bahusoid closed this as completed May 7, 2020
@bahusoid bahusoid marked this as a duplicate of #1860 May 7, 2020
@bahusoid
Copy link
Member

You can use development builds to verify that it actually fixes your issue. See here for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants