21

私はdapper-dot-netをORMとして使用しており、次の低速実行(1700ms)のSQLコードを生成します。

exec sp_executesql N'SELECT TOP 5 SensorValue FROM "Values" 
   WHERE DeviceId IN (@id1,@id2) AND SensorId = @sensor 
       AND SensorValue != -32768 AND SensorValue != -32767',N'@id1 
           bigint,@id2 bigint,@sensor int',@id1=139,@id2=726,@sensor=178

パラメータを削除してこのコードを変更すると、クエリは非常に高速(20ms)で実行されます。これらのパラメータの欠如が実際にこの大きな違いを生むべきでしょうか、そしてその理由は何ですか?

exec sp_executesql N'SELECT TOP 5 SensorValue FROM "Values" 
   WHERE DeviceId IN (139,726) AND SensorId = 178 
       AND SensorValue != -32768 AND SensorValue != -32767'
4

2 に答える 2

36

最後に OPTION (RECOMPILE) を追加

... AND SensorValue != -32767 OPTION (RECOMPILE) 

「パラメータ盗聴」が発生していると思われます

その場合は、OPTION のままにしておくか、代替案を検討できます。

更新 1

次の記事では、「パラメータ スニッフィング」について紹介しますhttp://pratchev.blogspot.be/2007/08/parameter-sniffing.html

SQL Server の内部 (噛むことができる) をよりよく理解できるようになるため、詳細を知ることをお勧めします。

それを理解していれば、オプション recompile とのトレードオフにより、ステートメントが頻繁実行される場合にパフォーマンスが低下する可能性があることがわかります。

根本的な原因がパラメーターのスニッフィングであることがわかった後、個人的にオプションの再コンパイルを追加し、パフォーマンスの問題がない限りそのままにしておきます。不適切なパラメータ スニッフィングを回避するためにステートメントを書き直すと、意図が失われ、保守性が低下します。しかし、書き直しが正当化される場合もあります (そうする場合は、適切なコメントを使用してください)。

更新 2

このテーマについて私が読んだ最も良いものは、第 32 章の「パラメーター スニッフィング: あなたの親友... それがそばにいないときを除いて」というものでした by GRANT FRITCHEY

おすすめです。

SQL Server MVP の詳細、第 2 巻

于 2012-06-07T14:01:43.440 に答える
9

最近、同じ問題に遭遇しました。最初に行ったのは、where ステートメントの列に NonClustered Covering Index を追加することでした。

これにより SQL の実行時間は改善されましたが、dapper がクエリを実行しているときは依然として遅く、実際にはタイムアウトしていました。

次に、dapper によって生成されたクエリがパラメーターを nvarchar(4000) として渡していることに気付きました。ここで、私の db テーブルの列は varchar(80) であったため、シークではなくインデックス スキャンが実行されました (以下をお読みになることをお勧めします)。それが意味をなさない場合は、索引を付けてください。) これに気づいたとき、私は自分のdapper whereステートメントを次のように更新しました:

WHERE 参照 = convert(varchar(80),@Reference)

上記の where ステートメントを使用して を実行すると、インデックス シークが発生し、パフォーマンスが 100% 向上しました。

追加するだけです:オプション(再コンパイル)は私にとってはうまくいきませんでした。

そして、このすべての歌とダンスの後、デフォルトでこれを行うように dapper に指示する方法があります。

Dapper.SqlMapper.AddTypeMap(typeof(string), System.Data.DbType.AnsiString);

これにより、デフォルトで、任意の文字列パラメーターが nvarchar (4000) ではなく varchar (4000) にマップされます。Unicode 文字列の比較が必要な場合は、パラメーターに対して明示的に変換を行うことができます。

于 2015-07-17T12:48:15.697 に答える