1

Ok, so I have this query that takes 2-5 seconds to run within Sql Management Studio. But when I am running it via my .net application, It exceeds the CommandTimeout of 5 minutes, every time.

I know the .net code works, because this same code (below) is executing other queries fine, and is delivering results.

public DataTable ExecuteQuery()
    {
        DataTable result = new DataTable();
        FoSqlConn con = new FoSqlConn(ConnectionToUse, ApplicationName); // connection string factory
        List<string> parameterNames = GetAllParametersFromQueryString(QueryString);
        using (SqlConnection sqlCon = new SqlConnection(con.GetConnectionString()))
        {
            using (SqlCommand cmd = new SqlCommand(QueryString, sqlCon))
            {
                if (DefaultTimeout.HasValue == true)
                {
                    cmd.CommandTimeout = DefaultTimeout.Value;
                }
                foreach (string paramName in parameterNames)
                {
                    if (Context.ParameterExists(paramName))
                    {
                        cmd.Parameters.AddWithValue(paramName, Context.GetParameterByName(paramName));
                    }
                    else
                    {
                        cmd.Parameters.AddWithValue(paramName, DBNull.Value);
                    }
                }
                sqlCon.Open();
                using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
                {
                    adapter.Fill(result);
                }
                if (sqlCon.State == ConnectionState.Open)
                {
                    con.CloseConnection();
                }
            }
        }

        return result;
    }

Below is the query, but with tables renamed:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
IF (@StartDate IS NULL)
BEGIN 
    SET @StartDate = DATEADD(Day, -60, GETDATE())
END 

IF (@EndDate IS NULL)
BEGIN
    SET @EndDate = DATEADD(DAY, -1, GETDATE())
END

SELECT
    P.ProductionObjDimId
    ,Dim.ProductionObjSourceId
    ,Dim.Name as WellName
    ,Dim.CurrentStatus
    ,Dim.ApiCode
    ,Dim.CurrentType
    ,Dim.StateProvidenceCode
FROM 
    ProductionDetail as P with(nolock)

JOIN DataWarehouse.dbo.ProductionObjMetaData as M
ON  P.ProductionObjDimId = M.ProductionObjDimId
AND M.OperationType = 1

JOIN DataWarehouse.dbo.ProductionObjDim as Dim
ON P.ProductionObjDimId = Dim.ProductionObjDimId

LEFT OUTER JOIN ProductionForecastingLinksView as Forcast
ON  Dim.ProductionObjSourceId = Forcast.comp_sk
AND Forcast.StartDate <= @EndDate
AND Forcast.EndDate > @StartDate

LEFT OUTER JOIN DataWarehouse.dbo.ForecastingUpload as Upload
ON Forcast.propnum = Upload.ForecastingWellSourceId
AND Upload.StartDate <= @EndDate
AND Upload.EndDate > @StartDate
AND (Upload.UploadDaily = 1 OR Upload.UploadMonthly = 1)
WHERE 
    P.ProductionDate >= @StartDate
AND
    Upload.ForecastingWellSourceId IS NULL
GROUP BY
    P.ProductionObjDimId
    ,Forcast.propnum        
    ,Dim.ProductionObjSourceId
    ,Dim.Name
    ,Dim.CurrentStatus
    ,Dim.ApiCode
    ,Dim.CurrentType
    ,Dim.StateProvidenceCode
Having 
    SUM(P.GrossOilProduction) > 0
OR  SUM(P.GrossGasSale) > 0
order by WellName

Please help, I am at a total loss for why this one query is having issues.

UPDATE (old, found while the below is interesting, it is not causing the problem) So I ran the trace, looking for the query, it showed up when I ran the query manually, but when I ran it through the code, it wasn't appearing at all, and got the same error message. So i really looked at the connection string, and I noticed something strange. While the user name and password were being passed, the SqlConnection object's ConnectionString property was missing the Password. I don't know if that points to a solution, but I am very confused now.

UPDATE #2 I didn't let the trace run long enough. I was able to capture the call that was super long.

exec sp_executesql N'SET TRANSACTION ISOLATION...[SAME CODE AS ABOVE]' ,@StartDate=NULL,@EndDate=NULL   

Running this exact query, I am getting the same result (it actually completes, it just takes 5+ minutes running it via this method, rather than the 3 seconds running the query directly). Note I did try to run the query with the parameters specified as nvarchar(4000) as well, but just running the query in Sql management studio works fine.

UPDATE #3 I have updated the statistics for all the tables that are joined within the query, no luck. The sp_executeSQL query still takes close to 5 minutes (its about 30 seconds less than before the rebuild of the statistics). At this point I am at a loss. Any Ideas?

UPDATE #4 finally found the solution! the problem was due to "Parameter Sniffing" I was using if conditions prior to my result generating query. the execution plan engine was assuming that the parameters, when passed as null, would hit the query as null, which is not the case. They always would have a value. To correct the problem, i removed the if conditions at the beginning of the query, and placed ISNULL checks where ever the parameter was used. this notified the execution plan of my intentions, and the sp_executeSQL call executed the same speed as my Sql Management Studio execution. Thank you all for your help!

2 Answers 2

1

Try testing with SQL Profiler.

Check to see if the sql command is making it to the database when you think it is and isn't being delayed.

Also, check the actual text of the query as received by the database and then run that text in Management Studio. It's possible the database is receiving something that is not quite what you are expecting.

Sign up to request clarification or add additional context in comments.

5 Comments

So the profiler was finding my Sql Management Studio run, but not my .net executed query. I just filtered using the TextData filter with the read uncommitted line, since this is the only query using that statement. the wierdest thing was that the ConnectionString, once within the SqlConnection object, was missing the password, but it was in the given string constructor variable. very strange
The statistics may be out of date, but it is also possible that you are getting two different execution plans. Try running both the raw query and the sp_executesql version in Sql Management Studio and compare the execution plans (msdn.microsoft.com/en-us/library/ms178071.aspx). Are they the same?
thanks, I did compare, and they were different. I just refreshed the execution plans, and the sp_executeSQL call still produces the extremely slow result. one thing to note though, is that I am using a view within my join. I did update the statistics on the view's tables as well though...
Here's a good article on Execution Plan Hints: simple-talk.com/sql/performance/… See if you can get the two execution plans to match.
Heh, I just found that article a few minutes ago! I'm marking your answer correct, but at this time I'm still at a loss of why running the query directly generates a totally different, and more efficent, execution plan than executing the same sql through the sp_ExecuteSQL. I am going to open a question on that one.
1

It is almost certainly an incorrectly cached query plan (this is the classic symptom). This is often the result of out of date statistics.

I suggest you update statistics.

One way to check whether statistics are 'skewed' or out of date, is to run your query with the Actual Execution plan turned on, and then examine the estimated rows versus actual rows in each operator.

UPDATE (in response to comments): You could try rebuilding all your indexes. As a last resort you could try marking the Stored Procedure with AS RECOMPILE, which is essentially what happens when you run through SQL Server Management Studio (SSMS). This would conclusively determine if it is an inappropriate cached query plan. If it is, it may be possible to mark up the stored proc with OPTIMIZE FOR.

3 Comments

Found the difference between the .net code and the query run from Sql Management Studio is the execution via the sp_executesql procedure. (running the query via this procedure takes 5 minutes, while sql management studio directly takes less than 3 seconds)
Ok, So I updated the statistics, which should have cleared the execution plan, but in fact, it still generated the same crappy execution plan. I am not sure what else to do... edit I updated the statistics for every table that is involved with the query.
the issue was due to my If conditions. parameter sniffing was building the execution plan assuming the my @StartDate and @EndDate would be null, when in fact, they would never be passed as null. I swapped out the if conditions, and used the ISNULL method where ever the parameter was used, and it worked like a charm!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.