1

わかりましたので、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 の実行と同じ速度で実行されました。ご協力ありがとうございました!

4

2 に答える 2

1

ほとんどの場合、クエリ プランが正しくキャッシュされていません (これは典型的な症状です)。これは多くの場合、古い統計の結果です。

統計を更新することをお勧めします。

統計が「歪んでいる」または古くなっているかどうかを確認する 1 つの方法は、実際の実行プランをオンにしてクエリを実行し、各演算子の推定行と実際の行を調べることです。

更新(コメントへの返信): すべてのインデックスを再構築してみてください。最後の手段として、ストアド プロシージャを でマークしてみることができますAS RECOMPILE。これは、基本的に SQL Server Management Studio (SSMS) を実行したときに発生することです。これにより、不適切なキャッシュ クエリ プランであるかどうかを最終的に判断できます。そうであれば、ストアド プロシージャを でマークアップできる可能性がありますOPTIMIZE FOR

于 2011-03-25T15:33:57.873 に答える
1

SQL プロファイラーでテストしてみてください。

遅延していると思われるときに、SQL コマンドがデータベースに到達しているかどうかを確認してください。

また、データベースが受信したクエリの実際のテキストを確認し、そのテキストを Management Studio で実行します。データベースが、期待しているものとはまったく異なるものを受け取っている可能性があります。

于 2011-03-25T15:30:26.367 に答える