好的,所以我有这个查询需要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执行相同的速度。谢谢大家的帮助!
答案 0 :(得分:1)
尝试使用SQL事件探查器进行测试。
检查sql命令是否在您认为是并且没有被延迟时进入数据库。
此外,检查数据库收到的查询的实际文本,然后在Management Studio中运行该文本。数据库可能会收到的东西并不像您期望的那样。
答案 1 :(得分:1)
几乎可以肯定是一个错误缓存的查询计划(这是典型的症状)。这通常是过时统计数据的结果。
我建议你update statistics。
检查统计信息是“偏斜”还是过时的一种方法是在启用“实际执行”计划的情况下运行查询,然后检查每个运算符中的估计行数与实际行数。
更新(响应评论):您可以尝试重建所有索引。作为最后的手段,您可以尝试使用AS RECOMPILE
标记存储过程,这实际上是在运行SQL Server Management Studio(SSMS)时发生的情况。这将最终确定它是否是不适当的缓存查询计划。如果是,则可以使用OPTIMIZE FOR
标记存储过程。