わかりましたので、Sql Management Studio 内で実行するのに 2 ~ 5 秒かかるこのクエリがあります。しかし、.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
助けてください。この 1 つのクエリに問題がある理由がまったくわかりません。
更新(古い、以下が興味深いときに見つかりました。問題の原因ではありません) そこで、クエリを探してトレースを実行しました。クエリを手動で実行すると表示されましたが、コードを実行すると、そうではありませんでしたまったく表示されず、同じエラーメッセージが表示されました。そこで接続文字列をよく見てみると、何かおかしいことに気づきました。ユーザー名とパスワードが渡されたときに、SqlConnection オブジェクトの ConnectionString プロパティにパスワードがありませんでした。それが解決策を示しているかどうかはわかりませんが、今は非常に混乱しています。
更新 #2トレースを十分長く実行させませんでした。超ロングのコールを捉えることができました。
exec sp_executesql N'SET TRANSACTION ISOLATION...[SAME CODE AS ABOVE]' ,@StartDate=NULL,@EndDate=NULL
この正確なクエリを実行すると、同じ結果が得られます (実際には完了します。クエリを直接実行するのに 3 秒かかるのではなく、このメソッドを使用して実行すると 5 分以上かかります)。nvarchar(4000) として指定されたパラメーターを使用してクエリを実行しようとしたことにも注意してください。ただし、Sql 管理スタジオでクエリを実行するだけで問題なく動作します。
更新 #3 クエリ内で結合されているすべてのテーブルの統計を更新しましたが、うまくいきません。sp_executeSQL クエリにはまだ 5 分近くかかります (統計の再構築前よりも約 30 秒短縮されています)。この時点で、私は途方に暮れています。何か案は?
更新 #4がついに解決策を見つけました! この問題は、結果生成クエリの前に if 条件を使用していた「パラメータ スニッフィング」が原因でした。実行計画エンジンは、パラメーターが null として渡されると、クエリが null としてヒットすると想定していましたが、そうではありませんでした。それらには常に値があります。この問題を解決するために、クエリの先頭にある if 条件を削除し、パラメーターが使用された場所に ISNULL チェックを配置しました。これにより、私の意図が実行計画に通知され、sp_executeSQL 呼び出しは、Sql Management Studio の実行と同じ速度で実行されました。ご協力ありがとうございました!