フィルターされた検索を実装する最適な方法


17

フィルター処理された検索フォームを実装する際のご意見をお聞かせください。次の場合を想像してみましょう。

  • 多数の列を持つ1つの大きなテーブル
  • このSQL Serverを言うことは重要かもしれません

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

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

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

  2. 動的クエリを作成します。動的クエリは、アプリケーションによって指定された内容に従って構築されます。

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

あなたの意見で最善のアプローチは何でしょうか教えてください。


あなたは動的な解決に向かっていると以下に述べます。それは素晴らしいです。可能なフィルターを列挙し、それらをサポートするインデックスを持っていることを確認してください。クエリが一貫して構築されている限り、それらは効率的でなければなりません。
マシューフリン

回答:


10

この同様の質問への答えをこちらでご覧ください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つの必須フィルターがある場合、上記のPROCは正常に実行されることです。

ただし、すべてのフィルターがオプションである場合、かなりひどい真実は、パラメーター化された動的SQLのパフォーマンスが実際に向上することです(オプションのパラメーターの順列ごとにN!の異なる静的PROCSを記述しない限り)。

以下のような動的SQLは、クエリパラメーターの順列ごとに異なるプランを作成してキャッシュしますが、少なくとも各プランは特定のクエリに合わせて「調整」されます(PROCかアドホック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を同様の方法で使用していることは注目に値します。


1
ええ、私はそう思いました、これは私が選択したオプションです。それが良いものであることを確認したかっただけです。回答ありがとうございます。
j0N45

「SQLステートメントがパラメーターなしで実行される場合、SQL Serverはステートメントを内部でパラメーター化して、既存の実行プランと一致する可能性を高めます。このプロセスは単純パラメーター化と呼ばれます。」したがって、基本的にプログラムは「where filenumber = + filename」のようなものを使用できます。もちろん、それはワームの缶を開きますが、それは別のトピック
です;

5

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

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


さて、私はすでにオプション2を実装しており、主にワイルドカードによってパフォーマンスが劇的に低下するため、最善の方法だと思いますが、コードの複雑さが増すため、メンテナンスを犠牲にしています。誰かがこのような状況に適したオプションを知っているかどうかを知りたいだけです。
j0N45

私はあなたに賛成票を投じますが、残念な評判はありません。
j0N45
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.