web-dev-qa-db-ja.com

フィルター検索を実装するための最良の方法

フィルター検索フォームの実装に関して、ご意見をお聞かせください。次のケースを想像してみましょう:

  • 列がたくさんある大きなテーブル
  • このSQL Serverは、

このテーブルのデータを検索するためのフォームを実装する必要があります。このフォームには、この検索をコスト化するためのいくつかのチェックボックスがあります。

ここで私の質問は、次のうちどれが検索を実装するための最良の方法であるべきかということです?

  1. 内部にクエリを含むストアドプロシージャを作成します。このストアドプロシージャは、アプリケーションによってパラメーターが指定されているかどうかをチェックし、パラメーターが指定されていない場合は、クエリにワイルドカードが挿入されます。

  2. 動的クエリを作成します。これは、アプリケーションによって提供されたものに従って作成されます。

パフォーマンスを最適化するためにストアドプロシージャの作成時にSQL Serverが実行プランを作成することがわかっているため、これを求めていますが、ストアドプロシージャ内に動的クエリを作成することで、実行プランによって得られる最適化を犠牲にしますか?

あなたの意見に最もふさわしいアプローチを教えてください。

17
j0N45

あなたはここでこの同様の質問への答えを見てみたいかもしれません: https://stackoverflow.com/questions/11329823/add-where-clauses-to-sql-dynamically-programmatically

一連のオプションパラメータを受け取り、次のようにフィルタを実装するSPROCが見つかりました。

CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS 
...
SELECT field1, field2, ... FROM [Table]
WHERE 
  (@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
  AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)

で実行される最初の実行プラン(例:@optionalParam1 = 'Hello World', @optionalParam2 = NULL)をキャッシュしますが、オプションのパラメーターの別のセット(例:@optionalParam1 = NULL, @optionalParam2 = 42)を渡すと、惨めに実行されます。 (もちろん、キャッシュされたプランのパフォーマンスが必要なので、WITH RECOMPILEはアウトです)

ここでの例外は、オプションのパラメーターに加えて、高度に選択的で適切にインデックス付けされたクエリに少なくとも1つのMANDATORYフィルターがある場合、上記のPROCは正常に実行されます。

ただし、すべてのフィルターがオプションの場合、パラメーター化された動的SQLの実際のパフォーマンスはかなり悪くなります(オプションパラメーターの置換ごとにN!種類の静的PROCSを記述しない限り)。

以下のような動的SQLは、クエリパラメーターの順列ごとに異なるプランを作成してキャッシュしますが、少なくとも各プランは特定のクエリに「調整」されます(PROCとAdhoc SQLのどちらであるかは関係ありません。パラメータ化されたクエリである限り、キャッシュされます)

したがって、私の好み:

DECLARE @SQL NVARCHAR(MAX)        

-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'

IF @OptionalParam1 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'    
    END        

IF @OptionalParam2 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'    
    END        

EXEC sp_executesql @SQL,        
    N'@optionalParam1 NVARCHAR(50), 
      @optionalParam2 INT'
    ,@optionalParam1 = @optionalParam1
    ,@optionalParam2 = @optionalParam2

などsp_executesqlに冗長パラメーターを渡しても問題ありません-それらは無視されます。 Linq2SQLやEFなどのORMは、パラメーター化された動的SQLを同様の方法で使用することに注意してください。

述語がまだ適用されているかどうかを追跡し、最初のANDを条件付きで2番目以降の述語にのみ適用する場合も、ひどい1 == 1ハックを回避できます。述語がまったくない場合は、WHEREも消えます。

動的クエリにもかかわらず、存在する場合でもフィルターはparameterizingであるため、SQLインジェクション攻撃に対する少なくとも最初の防御策があることに注意してください。

11
StuartLC

実装しやすいと思うものから始めます(オプション2と思います)。次にmeasure実世界のデータのパフォーマンスを測定します。事前ではなく、必要なときにのみ最適化を開始します。

ちなみに、検索フィルターの複雑さによっては、動的SQLがないとタスクを簡単に解決できない場合があります。したがって、ストアドプロシージャを使用する場合でも、既に疑っているように、パフォーマンスが向上することはほとんどありません。一方、役立つ場合は、いくつかのタイプのヒントがあります( http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/)を参照してください )動的かどうかにかかわらず、SQLクエリにSQLを追加して、SQLサーバーがその実行計画を最適化できるようにします。

5
Doc Brown