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.  [ 9 posts ] 
Author Message
 Post subject: Strings are always passed to sp_executesql as nvarchar
PostPosted: Fri Nov 03, 2006 8:11 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
I've recently come across an interesting performance problem using SQL server and want to see whether anyone out there can help.

We have a large table (> 1,000,000 rows) which is mapped to an NHibernate entity and we need to locate the entity by a property which maps to a varchar database column.

We have an index on the column, so we expected that this index would be used by the execution planner...and it is, however rather than doing an index seek it's doing an index scan. This had me stumped for some time until I came across the following post:

http://sqljunkies.com/WebLog/sqlbi/arch ... 24249.aspx

This points out that if a column is of type varchar and an index is created (also varchar, obviously) then if a query is executed against this column but the value passed is an *nvarchar* then an index *scan* will be performed (rather than a seek) so that the values in the index can be converted to nvarchar before the comparison is performed, causing a pretty serious performance degradation.

The real issue here is that NHibernate executes it's queries using sp_executesql and all string parameters are passed as nvarchar, which triggers the above performance problem.

Obviously we *could* change the column data to nvarchar, but this really isn't what we want in our DB schema.

What I really want to know is whether there's some way that the parameter type passed to sp_executesql can be explicitly set to varchar.

Hope that's clear and (more importantly) that someone can help!

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 8:42 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
You could try using type="AnsiString" for properties mapped to varchar columns.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 9:44 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Hey Sergey,

Nope - that didn't seem to work. The SQL statement is still using nvarchar:

eg:
Code:
exec sp_executesql N'select entity0_.EntityID as entity1_0_ from Entities entity0_  where (entity0_.VarCharProperty=@p0)', N'@p0 nvarchar(4000)', @p0 = N'Some_String'


Whatever creates the query seems to automatically assume that the parameter type to sp_executesql is nvarchar.

Any other suggestions?

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 9:58 am 
Beginner
Beginner

Joined: Wed Jul 19, 2006 8:24 am
Posts: 35
I've wondered about this too. This can have a significant impact on performance.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 12:14 pm 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
After a bit of additional research it appears that the sp_executesql stored proc is being called automatically by the SqlCommand's class's implementation of IDbCommand.ExecuteReader(), and it's getting the parameter datatypes from the parameters in the Parameters collection.

I'm not yet clear on whether this is a problem where NHibernate is failing to set the IDbParameter.DBType to DBType.AnsiString or whether it's a problem with the SqlCommand not interpreting this type correctly.

If anyone else has any input it'd be appreciated.

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 2:45 pm 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Ok, this is essentially my own fault, so I'll document my findings so others don't get caught:

I had assumed that parameter type used in the SQL would be assigned by IQuery.SetParameter based on the entity property that was the target of the HQL clause in which the parameter was used.

The type seems to be guessed directly according to the type provided to IQuery.SetParameter, so if a System.String value is passed to IQuery.SetParameter will automatically be identified as DbType.String.

If, however, you use IQuery.SetAnsiString to explicitly specify the parameter as a varchar things work as expected, so my problem is solved.

I would be nice if NH could try to set the parameter type according to the target entity property...is this within the realms of possiblity? If so I'll create a JIRA issue.

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 3:14 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
It's not really possible right now because it would require us to have a good HQL parser in NH which we currently don't. H3.2 does such a thing however (with their ANTLR-based parser), so it is possible in theory.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 3:33 pm 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Thank Sergey,

Until we've caught up I'll use IQuery.SetAnsiString. :)

Cheers,

Symon.


Top
 Profile  
 
 Post subject: AnsiString
PostPosted: Tue Dec 26, 2006 7:09 pm 
Newbie

Joined: Tue Dec 26, 2006 7:03 pm
Posts: 2
Hi,

I run in the same performance problem, what I dit, and it worked; was to change the type from String to AnsiString in the XML of the involved tables. Remember that the mappings are embeded in the VS .NET project, so it is necessary to rebuild the project/solution, to make the changes active.

No other changes to code were necessary.

My current development environment is:

V Studio 2003
C#
NHibernate 1.0.2
SQL Server 2000

I hope this helps

DiegoL


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 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.