Hi!
We are struggling with a strange problem: a SP become extremely slow when raw SQL is executed fairly fast.
1. we have
-MS SQL Server 2008 R2 Express Edition SP1 10.50.2500.0 with several databases on it.
-a database (it's size is around 747Mb)
-a stored procedure which takes different parameters and does select among multiple tables from the database.
The stored procedure was working pretty good and fast (it's execution usually took 1-2 seconds).
Example of call
Basically during execution of the stored procedure the executed 3 SQL query, the first Select Into query takes 99% of time.
This query is
2. This stored proc, after massive data update on the database (a lot tables and rows were affected by the update, however DB size was almost unchanged, now it is 752 ) become to work extremely slow. Now it takes from 20 to 90 seconds.
3. If I take raw SQL query from the stored procedure - it is executed within 1-2 seconds.
we've tried:
a) the SP is created with parameters
b) recreate the SP with parameter **with recompile**
c) execute the SP after purging prod cache **DBCC FREEPROCCACHE**
d) move part of where clauses into the join part
e) reindex tables
f) update statistics for the tables from the query using statements like **UPDATE STATISTICS Media WITH FULLSCAN**
However the execution of the stored procedure is still >> 30 seconds.
But if I run the SQL query which is generated by the SP - it is executed for less than 2 seconds.
I've compared execution plans for SP and for the raw SQL - they are quite different. During execution of RAW SQL - the optimizer is using Merge Joins, but when we execute SP - it uses Hash Match (Inner Join), like there are no indexes.
Execution Plan for RAW SQl - Fast
Execution Plan for SP - Slow
If someone knows what could it be - please help. Thanks in advance!
We are struggling with a strange problem: a SP become extremely slow when raw SQL is executed fairly fast.
1. we have
-MS SQL Server 2008 R2 Express Edition SP1 10.50.2500.0 with several databases on it.
-a database (it's size is around 747Mb)
-a stored procedure which takes different parameters and does select among multiple tables from the database.
ALTER Procedure [dbo].[spGetMovieShortDataList]( @MediaID int = null, @Rfa nvarchar(8) = null, @LicenseWindow nvarchar(8) = null, @OwnerID uniqueidentifier = null, @LicenseType nvarchar(max) = null, @PriceGroupID uniqueidentifier = null, @Format nvarchar(max) = null, @GenreID uniqueidentifier = null, @Title nvarchar(max) = null, @Actor nvarchar(max) = null, @ProductionCountryID uniqueidentifier = null, @DontReturnMoviesWithNoLicense bit = 0, @DontReturnNotReadyMovies bit = 0, @take int = 10, @skip int = 0, @order nvarchar(max) = null, @asc bit = 1 ) as begin declare @SQLString nvarchar(max); declare @ascending nvarchar(5); declare @ParmDefinition nvarchar(max); declare @now DateTime; set @ParmDefinition='@MediaID int, @Rfa nvarchar(8), @LicenseWindow nvarchar(8), @OwnerID uniqueidentifier, @LicenseType nvarchar(max), @PriceGroupID uniqueidentifier, @Format nvarchar(max), @GenreID uniqueidentifier, @Title nvarchar(max), @Actor nvarchar(max), @ProductionCountryID uniqueidentifier, @DontReturnMoviesWithNoLicense bit = 0, @DontReturnNotReadyMovies bit = 0, @take int, @skip int, @now DateTime'; set @ascending = case when @asc = 1 then 'ASC' else 'DESC' end set @now = GetDate(); set @SQLString=' SELECT distinct m.ID, m.EpisodNo, m.MediaID, p.Dubbed, pf.Format, t.OriginalTitle into #temp FROM Media m inner join Asset a1 on m.ID=a1.ID inner join Asset a2 on a1.ParentID=a2.ID inner join Asset a3 on a2.ParentID=a3.ID inner join Title t on t.ID = a3.ID inner join Product p on a2.ID = p.ID left join AssetReady ar on ar.AssetID = a1.ID left join License l on l.ProductID=p.ID left join ProductFormat pf on pf.ID = p.Format '+ CASE WHEN @PriceGroupID IS NOT NULL THEN 'left join LicenseToPriceGroup lpg on lpg.LicenseID = l.ID ' ELSE '' END+ CASE WHEN @Title IS NOT NULL THEN 'left join LanguageAsset la on la.AssetID = m.ID ' ELSE '' END+ CASE WHEN @LicenseType IS NOT NULL THEN 'left join LicenseType lt on lt.ID=l.LicenseTypeID ' ELSE '' END+ CASE WHEN @Actor IS NOT NULL THEN 'left join Cast c on c.AssetID = a1.ID ' ELSE '' END+ CASE WHEN @GenreID IS NOT NULL THEN 'left join ListToCountryToAsset lca on lca.AssetID=a1.ID ' ELSE '' END+ CASE WHEN @ProductionCountryID IS NOT NULL THEN 'left join ProductionCountryToAsset pca on pca.AssetID=t.ID ' ELSE '' END+ 'where ( 1 = case when @Rfa = ''All'' then 1 when @Rfa = ''Ready'' then ar.Rfa when @Rfa = ''NotReady'' and (l.TbaWindowStart is null OR l.TbaWindowStart = 0) and ar.Rfa = 0 and ar.SkipRfa = 0 then 1 when @Rfa = ''Skipped'' and ar.SkipRfa = 1 then 1 end) '+ CASE WHEN @LicenseWindow IS NOT NULL THEN 'AND 1 = (case when (@LicenseWindow = 1 And (l.WindowEnd < @now and l.TbaWindowEnd = 0)) then 1 when (@LicenseWindow = 2 And (l.TbaWindowStart = 0 and l.WindowStart < @now and (l.TbaWindowEnd = 1 or l.WindowEnd > @now))) then 1 when (@LicenseWindow = 4 And ((l.TbaWindowStart = 1 or l.WindowStart > @now) and (l.TbaWindowEnd = 1 or l.WindowEnd > @now))) then 1 when (@LicenseWindow = 3 And ((l.WindowEnd < @now and l.TbaWindowEnd = 0) or (l.TbaWindowStart = 0 and l.WindowStart < @now and (l.TbaWindowEnd = 1 or l.WindowEnd > @now)))) then 1 when (@LicenseWindow = 5 And ((l.WindowEnd < @now and l.TbaWindowEnd = 0) or ((l.TbaWindowStart = 1 or l.WindowStart > @now) and (l.TbaWindowEnd = 1 or l.WindowEnd > @now)))) then 1 when (@LicenseWindow = 6 And ((l.TbaWindowStart = 0 and l.WindowStart < @now and (l.TbaWindowEnd = 1 or l.WindowEnd > @now)) or ((l.TbaWindowStart = 1 or l.WindowStart > @now) and (l.TbaWindowEnd = 1 or l.WindowEnd > @now)))) then 1 when ((@LicenseWindow = 7 Or @LicenseWindow = 0) And ((l.WindowEnd < @now and l.TbaWindowEnd = 0) or (l.TbaWindowStart = 0 and l.WindowStart < @now and (l.TbaWindowEnd = 1 or l.WindowEnd > @now)) or ((l.TbaWindowStart = 1 or l.WindowStart > @now) and (l.TbaWindowEnd = 1 or l.WindowEnd > @now)))) then 1 end) ' ELSE '' END+ CASE WHEN @OwnerID IS NOT NULL THEN 'AND (l.OwnerID = @OwnerID) ' ELSE '' END+ CASE WHEN @MediaID IS NOT NULL THEN 'AND (m.MediaID = @MediaID) ' ELSE '' END+ CASE WHEN @LicenseType IS NOT NULL THEN 'AND (lt.Name = @LicenseType) ' ELSE '' END+ CASE WHEN @PriceGroupID IS NOT NULL THEN 'AND (lpg.PriceGroupID = @PriceGroupID) ' ELSE '' END+ CASE WHEN @Format IS NOT NULL THEN 'AND (pf.Format = @Format) ' ELSE '' END+ CASE WHEN @GenreID IS NOT NULL THEN 'AND (lca.ListID = @GenreID) ' ELSE '' END+ CASE WHEN @DontReturnMoviesWithNoLicense = 1 THEN 'AND (l.ID is not null) ' ELSE '' END+ CASE WHEN @Title IS NOT NULL THEN 'AND (t.OriginalTitle like N''%' + @Title + '%'' OR la.LocalTitle like N''%' + @Title + '%'') ' ELSE '' END+ CASE WHEN @Actor IS NOT NULL THEN 'AND (rtrim(ltrim(replace(c.FirstName + '' '' + c.MiddleName + '' '' + c.LastName, '' '', '' ''))) like ''%'' + rtrim(ltrim(replace(@Actor,'' '','' ''))) + ''%'') ' ELSE '' END+ CASE WHEN @DontReturnNotReadyMovies = 1 THEN 'AND ((ar.ID is not null) AND (ar.Ready = 1) AND (ar.CountryID = l.CountryID))' ELSE '' END+ CASE WHEN @ProductionCountryID IS NOT NULL THEN 'AND (pca.ProductionCountryID = @ProductionCountryID)' ELSE '' END+ ' select #temp.* ,ROW_NUMBER() over (order by '; if @order = 'Title' begin set @SQLString = @SQLString + 'OriginalTitle'; end else if @order = 'MediaID' begin set @SQLString = @SQLString + 'MediaID'; end else begin set @SQLString = @SQLString + 'ID'; end set @SQLString = @SQLString + ' ' + @ascending + ' ) rn into #numbered from #temp declare @count int; select @count = MAX(#numbered.rn) from #numbered while (@skip >= @count ) begin set @skip = @skip - @take; end select ID, MediaID, EpisodNo, Dubbed, Format, OriginalTitle, @count TotalCount from #numbered where rn between @skip and @skip + @take drop table #temp drop table #numbered'; execute sp_executesql @SQLString,@ParmDefinition, @MediaID, @Rfa, @LicenseWindow, @OwnerID, @LicenseType, @PriceGroupID, @Format, @GenreID, @Title, @Actor, @ProductionCountryID, @DontReturnMoviesWithNoLicense,@DontReturnNotReadyMovies, @take, @skip, @now end
The stored procedure was working pretty good and fast (it's execution usually took 1-2 seconds).
Example of call
DBCC FREEPROCCACHE EXEC value = [dbo].[spGetMovieShortDataList] @LicenseWindow =N'1', @Rfa = N'NotReady', @DontReturnMoviesWithNoLicense = False, @DontReturnNotReadyMovies = True, @take = 20, @skip = 0, @asc = False, @order = N'ID'
Basically during execution of the stored procedure the executed 3 SQL query, the first Select Into query takes 99% of time.
This query is
declare @now DateTime; set @now = GetDate(); SELECT distinct m.ID, m.EpisodNo, m.MediaID, p.Dubbed, pf.Format, t.OriginalTitle FROM Media m inner join Asset a1 on m.ID=a1.ID inner join Asset a2 on a1.ParentID=a2.ID inner join Asset a3 on a2.ParentID=a3.ID inner join Title t on t.ID = a3.ID inner join Product p on a2.ID = p.ID left join AssetReady ar on ar.AssetID = a1.ID left join License l on l.ProductID=p.ID left join ProductFormat pf on pf.ID = p.Format where ((l.TbaWindowStart is null OR l.TbaWindowStart = 0) and ar.Rfa = 0 and ar.SkipRfa = 0 ) And (l.WindowEnd < @now and l.TbaWindowEnd = 0 ) AND ((ar.ID is not null) AND (ar.Ready = 1) AND (ar.CountryID = l.CountryID))
2. This stored proc, after massive data update on the database (a lot tables and rows were affected by the update, however DB size was almost unchanged, now it is 752 ) become to work extremely slow. Now it takes from 20 to 90 seconds.
3. If I take raw SQL query from the stored procedure - it is executed within 1-2 seconds.
we've tried:
a) the SP is created with parameters
SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON
b) recreate the SP with parameter **with recompile**
c) execute the SP after purging prod cache **DBCC FREEPROCCACHE**
d) move part of where clauses into the join part
e) reindex tables
f) update statistics for the tables from the query using statements like **UPDATE STATISTICS Media WITH FULLSCAN**
However the execution of the stored procedure is still >> 30 seconds.
But if I run the SQL query which is generated by the SP - it is executed for less than 2 seconds.
I've compared execution plans for SP and for the raw SQL - they are quite different. During execution of RAW SQL - the optimizer is using Merge Joins, but when we execute SP - it uses Hash Match (Inner Join), like there are no indexes.
Execution Plan for RAW SQl - Fast
Execution Plan for SP - Slow
If someone knows what could it be - please help. Thanks in advance!