There _are_ some places where you can modify the SQL, but it's usually
hacky.
Your solution is probably the best compromise.

    Diego


On Mon, Nov 15, 2010 at 12:25, Michael Smith <[email protected]> wrote:

> So, I guess the answer is: "It is not possible to join with a parameterized
> function or specify specific join hints without manually constructing the
> entire SQL using CreateSQLQuery".  That's what I assumed, but I know there
> are lot of hooks into NHibernate that I have yet to learn, so I wanted to
> make sure.
>
> We were able to re-write the function call into a single SQL query and add
> that into the criteria using criteria.Add(Expression.Sql(...)) and
> achieved the appropriate execution plan and performance.  That saves us from
> needing to manually construct the rest of the SQL query.  It's quite a bit
> messy for just the expression, but still considerably better than having to
> construct the whole query using CreateSQLQuery.
>
> Regards,
> Michael
>
> On Sun, Nov 14, 2010 at 8:26 AM, Diego Mijelshon 
> <[email protected]>wrote:
>
>> If you need a specific SQL, the best way to use it is with CreateSQLQuery.
>> There's a whole chapter dedicated to that:
>> http://nhforge.org/doc/nh/en/index.html#querysql
>>
>>     Diego
>>
>>
>> On Mon, Nov 8, 2010 at 19:22, Michael Smith <[email protected]>wrote:
>>
>>> I'm using the Criteria API to build up a highly variable query.  This is
>>> working great for returning the proper results based on the inputs, but in
>>> some circumstances, performance is abysmal.  Our DBA is recommending a
>>> specific query optimization that addresses these issues, but I am unable to
>>> determine how to translate this into NHibernate query code.
>>>
>>> The simplest query that demonstrates the problem is created using
>>> something like the following usage of the Criteria API:
>>>
>>> int inputX = ...;
>>> string inputY = ...;
>>>
>>> DetachedCriteria criteria = DetachedCriteria.For(typeof(MappedEntity));
>>>
>>> SqlString sql = new SqlString
>>>     ("{alias}.ID in (select ID FROM [dbo].[UserDefinedFunction](",
>>>     Parameter.Placeholder, "))");
>>> criteria.Add(Expression.Sql(sql, inputX, NHibernateUtil.Int32));
>>>
>>> SqlString sql = new SqlString
>>>     ("{alias}.ProjectId in (",
>>>      "SELECT [Key] FROM CONTAINSTABLE(dbo.MappedEntity,*,",
>>>      Parameter.Placeholder,
>>>      "))");
>>> criteria.Add(Expression.Sql(sql, inputY, NHibernateUtil.String));
>>>
>>>
>>>
>>> This translates to the following SQL:
>>>
>>> SELECT ...
>>>  FROM dbo.MappedEntity this_
>>> WHERE this_.ID in (
>>>     SELECT ID
>>>     FROM [dbo].[UserDefinedFunction](@p0)
>>> )
>>> and this_.ID in (
>>>     SELECT [Key]
>>>     FROM CONTAINSTABLE(dbo.MappedEntity,*,@p1)
>>> )
>>>
>>>
>>> That SQL is exactly equivalent to the following with regards to the
>>> generated query plan and performance:
>>>
>>> SELECT ...
>>>  FROM dbo.MappedEntity this_
>>> INNER JOIN [dbo].[UserDefinedFunction](@p0) udf ON udf.ID = this_.ID
>>> WHERE this_.ID in (
>>>     SELECT [Key]
>>>     FROM CONTAINSTABLE(dbo.MappedEntity,*,@p1)
>>> )
>>>
>>>
>>>
>>> The performance issue is addressed by adding a "merge" join hint:
>>>
>>> SELECT ...
>>> FROM dbo.MappedEntity this_
>>> INNER *MERGE *JOIN [dbo].[UserDefinedFunction](@p0) udf
>>>     ON udf.ID = this_.ID
>>> WHERE this_.ID in (
>>>     SELECT [Key]
>>>     FROM CONTAINSTABLE(dbo.MappedEntity,*,@p1)
>>> )
>>>
>>>
>>> First off, is there any way to map a parameterized user-defined function
>>> such that we could even join with it (rather than having it in the where
>>> clause like we do now)?
>>>
>>> Secondly, if there is such a way, is there some method of providing join
>>> hints in the underlying sql?
>>>
>>> Any alternative suggestions are also welcome.
>>>
>>> Regards,
>>> Michael
>>>
>>> P.S.  Note:  the performance issues seem to be caused by SQL Server's
>>> query analyzer assuming that the user defined function returns a single row
>>> (since it can't maintain statistics on the temporary return table to know
>>> otherwise) and thus uses a nested loop to combine it with the additional
>>> restrictions.  Since there are thousands of matches rather than one, a merge
>>> join is much better than the nested loop.  We're simultaneously looking at
>>> ways to re-write the table-valued function to avoid the situation to begin
>>> with, but the odds of that are very small).
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "nhusers" group.
>>> To post to this group, send email to [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected]<nhusers%[email protected]>
>>> .
>>> For more options, visit this group at
>>> http://groups.google.com/group/nhusers?hl=en.
>>>
>>
>>  --
>> You received this message because you are subscribed to the Google Groups
>> "nhusers" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to
>> [email protected]<nhusers%[email protected]>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/nhusers?hl=en.
>>
>
>  --
> You received this message because you are subscribed to the Google Groups
> "nhusers" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected]<nhusers%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/nhusers?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/nhusers?hl=en.

Reply via email to