Every now and then we get this error from some of our old ASP pages that use a Stored Procedure to return a recordset(usually <2000 rows).
Microsoft OLE DB Provider for ODBC Drivers (0x80040E31)
[Microsoft][ODBC SQL Server Driver]Timeout expired
When I run the SP on the server it runs without an issue but with ASP it just gives a Timeout expired.
When I recompile the SP it fixes the issue and the SP works fine in ASP once more. But then # of days/weeks later I get the same problem either from the same SP/ASP or another. The source tables and ASP are not being changed at all.
It’s got me stumped.
Sample SP:
USE [DB-Name]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Procedure [dbo].[MY_StoredProcedure]
@Filter varchar(50) = null,
@SortOrder bit = 1,
@SortField varchar(50) = 'MyCol1',
@Page int = 1,
@RecordsPerPage int = 20
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #TempTable(RowID int IDENTITY,Col1 int,Col2 varchar(20),Col3 datetime)
INSERT INTO #TempTable
SELECT Col1, Col2, Col3 FROM [DB-Table]
WHERE
@Filter is null OR (
Col1 LIKE '%' + @Filter + '%'
OR Col2 LIKE '%' + @Filter + '%'
OR Col3 LIKE '%' + @Filter + '%'
)
ORDER By
CASE WHEN @SortField = 'MyCol1' AND @SortOrder = 1 THEN Col1 END ASC,
CASE WHEN @SortField = 'MyCol1' AND @SortOrder = 0 THEN Col1 END DESC,
CASE WHEN @SortField = 'MyCol2' AND @SortOrder = 0 THEN Col2 END DESC,
CASE WHEN @SortField = 'MYCol2' AND @SortOrder = 1 THEN Col2 END ASC,
CASE WHEN @SortField = 'MyCol3' AND @SortOrder = 1 THEN Col3 END ASC,
CASE WHEN @SortField = 'MyCol4' AND @SortOrder = 0 THEN Col3 END DESC
-- Find out the first and last record we want
DECLARE @FirstRec int, @LastRec int
SELECT @FirstRec = (@Page - 1) * @RecordsPerPage
SELECT @LastRec = (@Page * @RecordsPerPage + 1)
-- Now, return the set of paged records, plus, an indiciation of if we have more records or not!
SELECT *,TotalRecords=(SELECT COUNT(RowID) FROM #TempTable),MoreRecords=(SELECT COUNT(RowID) FROM #TempTable TI WHERE TI.RowID >= @LastRec)
FROM #TempTable
WHERE
RowID > @FirstRec AND RowID < @LastRec
DROP TABLE #TempTable
-- Turn NOCOUNT back OFF
SET NOCOUNT OFF
END
GO
What you have described sounds like an incorrectly cached query plan as a result of parameter sniffing.
It can sometimes be avoided by ensuring your statistics and indexes are up to date.
Suggest you post the stored procedure in question.
The canonical reference is: Slow in the Application, Fast in SSMS?
In SQL Server 2008 onwards you can make use of
OPTIMIZE FOR:This tells SQL Server to eliminate parameter sniffing for parameter
@Filter, and use an average selectivity value (based upon statistics).