好的,所以我有这个查询需要 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
请帮忙,我完全不知道为什么这个查询有问题。
更新(旧,虽然下面的内容很有趣,但它没有引起问题) 所以我运行跟踪,寻找查询,当我手动运行查询时它出现了,但是当我通过代码运行它时,它是'根本没有出现,并得到相同的错误消息。所以我真的查看了连接字符串,我发现了一些奇怪的东西。在传递用户名和密码时,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 秒)。在这一点上,我不知所措。有任何想法吗?
更新#4终于找到了解决方案!问题是由于我在结果生成查询之前使用了 if 条件的“参数嗅探”。执行计划引擎假设参数在作为 null 传递时会以 null 形式命中查询,但事实并非如此。它们总是有价值的。为了纠正这个问题,我删除了查询开头的 if 条件,并在使用参数的地方放置了 ISNULL 检查。这通知了我意图的执行计划,并且 sp_executeSQL 调用的执行速度与我的 Sql Management Studio 执行速度相同。感谢大家的帮助!