Recently we have introduced some stored procedure in the production and have found that it performs incredibly slow.
Our reasoning and tests in the development environment did not manifest any problem at all.
In essence that procedure executes some SELECT and returns a status as a signle output variable. Procedure recieves several input parameters, and the SELECT statement uses with(recompile) execution hint to optimize the performance for a specific parameters.
We have analyzed the execution plan of that procedure and have found that it works as if with(recompile) hint was not specified. Without that hint SELECT failed to use index seek but rather used index scan.
What we have lately found is that the same SELECT that produces result set instead of reading result into a variable performs very well.
We think that this is a bug in SQL Server 2008 R2 (and in SQL Server 2008).
To demonstrate the problem you can run this test:
-- Setup create table dbo.Items ( Item int not null primary key ); go insert into dbo.Items select 1 union all select 2 union all select 3 union all select 4 union all select 5 go create procedure dbo.GetMaxItem ( @odd bit = null, @result int output ) as begin set nocount on; with Items as ( select * from dbo.Items where @odd is null union all select * from dbo.Items where (@odd = 1) and ((Item & 1) = 1) union all select * from dbo.Items where (@odd = 0) and ((Item & 1) = 0) ) select @result = max(Item) from Items option(recompile); end; go create procedure dbo.GetMaxItem2 ( @odd bit = null, @result int output ) as begin set nocount on; declare @results table ( Item int ); with Items as ( select * from dbo.Items where @odd is null union all select * from dbo.Items where (@odd = 1) and ((Item & 1) = 1) union all select * from dbo.Items where (@odd = 0) and ((Item & 1) = 0) ) insert into @results select max(Item) from Items option(recompile); select @result = Item from @results; end; go
Test with output into a variable:
declare @result1 int; execute dbo.GetMaxItem @odd = null, @result = @result1 output
Test without output directly into a variable:
declare @result2 int; execute dbo.GetMaxItem2 @odd = null, @result = @result2 output
Now, you can see the difference: the first execution plan uses startup expressions, while the second optimizes execution branches, which are not really used. In our case it was crucial, as the execition time difference was minutes (and more in future) vs a split of second.
See also Microsoft Connect Entry.
Remember Me
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u