いくつかの統計結果を Web ビューに表示する複雑なクエリを作成しています。ビューには、ユーザーの選択に応じて、いくつかの異なるフィルターを含めることができます。また、ワイルドカードを使用する可能性もあります。
このクエリは、SqlParameters を使用して C# でプログラム的に作成しています。したがって、クエリは次のようになります。
sc.CommandText = "SELECT * FROM table
WHERE field1 = @filter1
AND field2 LIKE @filter2"; //...and more parameters
sc.SqlParameters.Add(
new SqlParameter("@filter1", SqlDbType.Int, 32) { Value = 1});
sc.SqlParameters.Add(
new SqlParameter("@filter2", SqlDbType.VarChar, 446) { Value = "whatever%"});
これは非常に単純化されたバージョンですが、クエリ自体は重要ではありません。さまざまなオプションのパラメーターを持つことができることに注意してください (これはかなり一般的な状況だと思います)。
Sql Manager でこのクエリを実行したとき、パラメーターを使用すると大幅に速度が低下することに気付きました。したがって、次の 2 つのクエリは同じはずですが、異なる実行プランを使用しているため、パラメーター化されたクエリの実行が大幅に遅くなります。
DECLARE @filter1 INT
DECLARE @filter2 VARCHAR 446
SET @filter1 = 1
SET @filter2 = "whatever%"
SELECT * FROM table WHERE field1 = @filter1 AND field2 LIKE @filter2
高速バージョン:
SELECT * FROM table WHERE field1 = 1 AND field2 LIKE 'whatever%'
同じ問題を抱えている人の別の例を次に示します。
パラメータ化されたクエリは、パラメータ化されていないクエリと比較して非常に遅いクエリプランを生成するのはなぜですか
parameter sniffingと呼ばれるものがあり、パラメーター化されたクエリの実行が遅くなる可能性がありますが、これはストアド プロシージャではないため、私の場合は当てはまりません。
提案された解決策の 1 つは、OPTION(RECOMPILE) または OPTION(OPTIMIZE FOR) を使用することです。フィルターに含まれているかどうかに関係なく、約 10 個のオプションのパラメーターがあり、このオプションはLIKE
.
だから、私は行き止まりにいると感じており、パラメーターを取り除き、コードで動的なリテラルクエリを構築することを考えています。しかし、その後、Sql インジェクションが登場します。
では、この問題を解決する方法について他に提案はありますか? または、パラメーターを安全にエスケープする方法を知っていますか?
編集: ここでは、次を使用して、1 つのパラメーターを持つクエリの実行プランを確認できますLIKE
。
編集:より単純化された代表的なクエリ実行計画: