2

継承して最適化しようとしている検索クエリがあります。誰かがそのようなベストプラクティスと推奨事項を持っているかどうか知りたい. 運用サーバーも SQL Server 2000 のままです。

クエリは、数百万件のレコード テーブルを検索するために、5 つの異なる検索基準パラメーター (名、姓、住所、電話番号など) を受け入れる高度な顧客検索ストアド プロシージャです。結合されたすべての列と WHERE 句の列にインデックスがあります。さらに、最初のクエリは、ページング容量のためにレコードをテーブル変数にダンプします。

INSERT INTO   @tempCustTable (CustomerID, FirstName, LastName, City, StateProvince, Zip, PhoneNumber)
SELECT  DISTINCT cu.CustomerID, cu.FirstName, cu.LastName, a.City,
a.StateProvince, a.Zip, p.PhoneNumber
FROM Customer cu WITH(NOLOCK)
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID
WHERE  (cu.LastName = @LastName OR cu.LastName LIKE @LastName + '%') 
AND (@FirstName IS NULL OR cu.FirstName = @FirstName OR cu.FirstName LIKE @FirstName + '%')
AND (@StateProvince = '' OR a.StateProvince LIKE @StateProvince)
AND (@City = '' OR a.City LIKE @City + '%')
AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%')
ORDER BY cu.LastName, cu.FirstName

クエリのパフォーマンスを向上させる方法について、誰かに推奨事項はありますか?

4

5 に答える 5

2

この行全体ではありません

AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%')

これと同じ

AND (a.Zip LIKE @Zip + '%')

確かに

AND (a.Zip LIKE @Zip + '%')

それはと同じです

a.Zip = @Zip OR a.Zip LIKE @Zip + '%'
于 2009-01-23T15:15:46.803 に答える
2

SQLMenace が最初に指摘したように、コード内の多くの冗長性を間違いなくクリーンアップできます。

もう 1 つのことは、ORDER BY を INSERT..SELECT と一緒に使用してはならないということです。このコンテキストでは、ORDER BY は無意味です。IDENTITY 列に特定の動作を強制するために使用することがありますが、それは IMO の悪い習慣です。

これがあなたの状況で役立つかどうかはわかりませんが、最近出くわしたことの1つは、ストアドプロシージャSQL Server(私は2005を使用していますが、おそらく2000にも当てはまります)ではORを短絡しないことです状態の場合が多い。たとえば、次を使用する場合:

@my_parameter IS NULL OR my_column = @my_parameter

@my_parameter に NULL 値を渡しても、後半は評価されます。これは、ストアド プロシージャを再コンパイル (および SELECT) するように設定した場合でも発生しました。その秘訣は、CASE ステートメントを使用して強制的に短絡させることでした。そのトリックを使用して(そして冗長性を取り除くと)、ステートメントは次のようになります。

INSERT INTO @tempCustTable
(
     CustomerID,
     FirstName,
     LastName,
     City,
     StateProvince,
     Zip,
     PhoneNumber
)
SELECT DISTINCT
     cu.CustomerID,
     cu.FirstName,
     cu.LastName,
     a.City,
     a.StateProvince,
     a.Zip,
     p.PhoneNumber
FROM Customer cu WITH(NOLOCK)
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID
WHERE
     (cu.LastName LIKE @LastName + '%') AND
     (1 =
          CASE
               WHEN @FirstName IS NULL THEN 1
               WHEN cu.FirstName LIKE @FirstName + '%' THEN 1
               ELSE 0
          END
     ) AND
     (1 =
          CASE
               WHEN @StateProvince = '' THEN 1
               WHEN a.StateProvince = @StateProvince THEN 1
               ELSE 0
          END
     ) AND
     (1 = CASE
               WHEN @City = '' THEN 1
               WHEN a.City LIKE @City + '%' THEN 1
               ELSE 0
          END
     ) AND
     (1 = CASE
               WHEN @Zip = '' THEN 1
               WHEN a.Zip LIKE @Zip + '%' THEN 1
               ELSE 0
          END
     )

クエリが長くなり、おそらくもう少し複雑になりますが、パフォーマンスを向上させるためには価値があるかもしれません。これは、条件にサブクエリが含まれている場合に特に当てはまります。

最後に...パラメータと一致させてください。@FirstName については、NULL 値をチェックして、それが使用されているかどうかを判断しますが、他のものについては空の文字列をチェックしています。基本的なコーディング 101 ここで注意する必要があります。

于 2009-01-23T18:37:48.033 に答える
1
  • 「OR」は避けてください。一般に、OR はインデックスの使用を妨げます。
  • 左側に「%」を入れないでください。- 同じ理由。
于 2009-01-23T15:10:41.540 に答える
0

動的SQLを使用してクエリを作成できます。これにより、ほとんどの OR が削除され、ユーザーが実際に入力したパラメーターの WHERE ステートメント行に含めるだけで済みます。

これを行う場合は、exec ではなく sp_executesql を使用して、動的 SQL をパラメーター化し、クエリ プランをキャッシュできるようにしてください。

于 2009-01-23T15:37:23.327 に答える
0

SQLコードに「%」を追加しないようにしますが、代わりに、アプリケーションで検証した後、パラメーターに既にそれが含まれていることを期待します! 次に、「=」比較を含めず、常に LIKE を使用します。

WHERE (cu.LastName LIKE @LastName)

それ以外の:

WHERE (cu.LastName = @LastName OR cu.LastName LIKE @LastName + '%')

于 2009-01-23T15:20:16.263 に答える