简单查询时间仅在.net SqlDataAdapter中

时间:2011-03-25 13:45:15

标签: .net sql sqldataadapter

好的,所以我有这个查询需要2-5秒才能在Sql Management Studio中运行。但是当我通过我的.net应用程序运行它时,它每次超过5分钟的CommandTimeout。

我知道.net代码有效,因为相同的代码(如下)正在执行其他查询,并且正在提供结果。

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;
    }

以下是查询,但重命名了表:

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

请帮助,我完全不知道为什么这个查询有问题。

UPDATE(旧的,发现虽然下面很有趣,但不会导致问题) 所以我运行跟踪,查找查询,它出现在我手动运行查询时,但当我通过代码运行它时,它根本没有出现,并得到相同的错误消息。所以我真的看了连接字符串,我发现了一些奇怪的东西。在传递用户名和密码时,SqlConnection对象的ConnectionString属性缺少密码。我不知道这是否指向解决方案,但我现在非常困惑。

更新#2 我没有让跟踪运行得足够长。我能够捕获超长的电话。

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

运行这个确切的查询,我得到相同的结果(它实际上完成,它只需要5分钟以上通过此方法运行它,而不是直接运行查询的3秒)。 注意我确实尝试使用指定为nvarchar(4000)的参数运行查询,但只是在Sql management studio中运行查询工作正常。

更新#3 我更新了查询中加入的所有表的统计信息,没有运气。 sp_executeSQL查询仍然需要接近5分钟(比重建统计信息之前少约30秒)。在这一点上,我不知所措。任何想法?

UPDATE#4 终于找到了解决方案!问题是由于我在结果生成查询之前的条件时使用的“参数嗅探”。执行计划引擎假设参数在作为null传递时会将查询命中为null,但情况并非如此。他们总是有价值。为了解决这个问题,我删除了查询开头的if条件,并放置了ISNULL检查使用参数的位置。这通知了我的意图的执行计划,并且sp_executeSQL调用执行与我的Sql Management Studio执行相同的速度。谢谢大家的帮助!

2 个答案:

答案 0 :(得分:1)

尝试使用SQL事件探查器进行测试。

检查sql命令是否在您认为是并且没有被延迟时进入数据库。

此外,检查数据库收到的查询的实际文本,然后在Management Studio中运行该文本。数据库可能会收到的东西并不像您期望的那样。

答案 1 :(得分:1)

几乎可以肯定是一个错误缓存的查询计划(这是典型的症状)。这通常是过时统计数据的结果。

我建议你update statistics

检查统计信息是“偏斜”还是过时的一种方法是在启用“实际执行”计划的情况下运行查询,然后检查每个运算符中的估计行数与实际行数。

更新(响应评论):您可以尝试重建所有索引。作为最后的手段,您可以尝试使用AS RECOMPILE标记存储过程,这实际上是在运行SQL Server Management Studio(SSMS)时发生的情况。这将最终确定它是否是不适当的缓存查询计划。如果是,则可以使用OPTIMIZE FOR标记存储过程。