6

テーブルの1つに約200万行のSQL2008R2データベースがあり、パラメーター化されたSQLを使用するときに特定のクエリのパフォーマンスに苦労しています。

テーブルには、名前を含むフィールドがあります。

[PatientsName] nvarchar NULL,

フィールドには簡単なインデックスもあります。


CREATE NONCLUSTERED INDEX [IX_Study_PatientsName] ON [dbo].[Study] 
(
    [PatientsName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [INDEXES]
GO

Management Studioでこのクエリを実行すると、実行に約4秒かかります。


declare @StudyPatientsName nvarchar(64)
set @StudyPatientsName= '%Jones%'

SELECT COUNT(*) FROM Study WHERE Study.PatientsName like @StudyPatientsName

しかし、このクエリを実行すると、次のようになります。


SELECT COUNT(*) FROM Study WHERE Study.PatientsName like '%Jones%'

実行には0.5秒以上かかります。

実行プランを見ると、パラメーター化されていないクエリは、上記のインデックスを使用してインデックススキャンを実行します。これは明らかに効率的です。パラメータ化されたクエリはインデックスを使用しますが、インデックスに対して範囲シークを実行します。

問題の一部は、主要なワイルドカードを持つことです。先頭のワイルドカードを削除すると、両方のクエリが数分の1秒で返されます。残念ながら、主要なワイルドカードをサポートする必要があります。

問題が発生した場所でパラメーター化されたクエリを実行する自家製のORMがあります。これらのクエリはユーザーからの入力に基づいて実行されるため、パラメーター化されたクエリはSQLインジェクション攻撃などを回避するのに意味があります。パラメータ化されたクエリ関数とパラメータ化されていないクエリを作成する方法があるかどうか疑問に思っていますか?

クエリオプティマイザにヒントを与えるさまざまな方法を調べて、オプティマイザに各クエリのクエリプランをやり直させようとしましたが、パフォーマンスを向上させるものはまだ見つかりませんでした。私はこのクエリを試しました:


SELECT COUNT(*) FROM Study WHERE Study.PatientsName like @StudyPatientsName
OPTION ( OPTIMIZE FOR (@StudyPatientsName = '%Jones%'))

これはこの質問の解決策として言及されましたが、違いはありませんでした。

どんな助けでもいただければ幸いです。

4

4 に答える 4

4

スキャンを強制したいようです。ヒントはありますが、FORCESEEK類似したヒントは見つかりませんでしFORCESCANた。しかし、これでうまくいくはずです。

SELECT COUNT(*) 
FROM Study 
WHERE Study.PatientsName + '' like @StudyPatientsName

たぶんあなたはあなたのデータで以下を試して、それがどのように機能するかを見ることができますが。

SELECT COUNT(*) 
FROM Study 
WHERE Study.PatientsName  like @StudyPatientsName
option (recompile)
于 2010-08-16T19:28:16.483 に答える
3

ここでパフォーマンスを向上させる最善のチャンスは、フルテキストインデックスの使用を検討することだと思います。

于 2010-08-16T16:55:54.143 に答える
0

これを確認するためのドキュメントを見つけるのに問題がありますが、IIRC、COUNT(*)はMS SQLで全表スキャンを実行します(キャッシュされた値を使用するのではありません)。nullにできない列やインデックスが定義されている列に対して実行すると、ここでも確認するドキュメントが見つからないため、ここでベースから外れる可能性があります)、より高速になると思います。

クエリを次のように変更するとどうなりますか。

SELECT COUNT(id) FROM Study WHERE Study.PatientsName Like @StudyPatientsName

また

SELECT COUNT(PatientsName) FROM Study 
WHERE Study.PatientsName 
LIKE @StudyPatientsName
于 2010-08-16T17:05:05.330 に答える
0

他のすべてが失敗した場合は、試すことができます

SELECT COUNT(*) FROM Study WITH(INDEX(0)) WHERE Study.PatientsName like @StudyPatientsName

おそらくあなたはそれをIFで包むことができます

IF substring(@StudyPatientsName, 1, 1) = '%'
    SELECT COUNT(*) FROM Study WITH(INDEX(0)) WHERE Study.PatientsName like @StudyPatientsName
ELSE
    SELECT COUNT(*) FROM Study WHERE Study.PatientsName like @StudyPatientsName

編集:マーティンが指摘したように、この特定のクエリでは、既存のインデックスのインデックススキャンの方が高速である可能性が高いため、これはおそらく最善の方法ではありません。ただし、同様の状況に適用できる可能性があります。

于 2010-08-17T13:33:42.800 に答える