web-dev-qa-db-ja.com

SqlDataAdapter.Fillメソッドが遅い

SQL Server Management Studioでの実行に1秒未満かかるのに、このコードを使用して9列89行のテーブルを返すストアドプロシージャが実行に60秒かかる(.NET 1.1)のはなぜですか?ローカルマシンで実行されているため、ネットワークレイテンシがほとんどない、またはない、高速な開発マシン

Dim command As SqlCommand = New SqlCommand(procName, CreateConnection())
command.CommandType = CommandType.StoredProcedure
command.CommandTimeout = _commandTimeOut
Try
   Dim adapter As new SqlDataAdapter(command)
   Dim i as Integer
   For i=0 to parameters.Length-1
      command.Parameters.Add(parameters(i))
   Next
   adapter.Fill(tableToFill)
   adapter.Dispose()
Finally
   command.Dispose()
End Try

私のパラメーター配列は型指定されています(このSQLの場合、パラメーターは1つだけです)

parameters(0) = New SqlParameter("@UserID", SqlDbType.BigInt, 0, ParameterDirection.Input, True, 19, 0, "", DataRowVersion.Current, userID)

ストアドプロシージャは、次のようなselectステートメントにすぎません。

ALTER PROC [dbo].[web_GetMyStuffFool]
   (@UserID BIGINT)
AS
SELECT Col1, Col2, Col3, Col3, Col3, Col3, Col3, Col3, Col3
FROM [Table]
31
Steve Wright

まず、パフォーマンスを適切にプロファイリングしていることを確認してください。たとえば、ADO.NETからクエリを2回実行して、2回目が1回目よりもはるかに速いかどうかを確認します。これにより、アプリのコンパイルとデバッグインフラストラクチャの立ち上げを待機するオーバーヘッドがなくなります。

次に、ADO.NETおよびSSMSのデフォルト設定を確認します。たとえば、SSMSでSET ARITHABORT OFFを実行すると、ADO.NETを使用するときと同じくらい遅く実行される場合があります。

SSMSでSET ARITHABORT OFFを実行すると、ストアドプロシージャが再コンパイルされたり、別の統計情報が使用されたりすることがありました。そして突然、SSMSとADO.NETの両方がほぼ同じ実行時間を報告していました。

これを確認するには、各実行の実行プラン、特にsyscacheobjectsテーブルを確認します。それらはおそらく異なるでしょう。

特定のストアドプロシージャで 'sp_recompile'を実行すると、関連する実行プランがキャッシュから削除されます。これにより、SQL Serverは、プロシージャの次回の実行時に、より適切なプランを作成できるようになります。

最後に、「 nuke it from orbit 」アプローチを試して、SSMSを使用してプロシージャキャッシュとメモリバッファ全体を消去することができます。

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

クエリをテストする前にこれを行うと、キャッシュされた実行プランと以前の結果キャッシュを使用できなくなります。

47
RoadWarrior

これが私がやったことです:

次のSQLステートメントを実行して、データベース内のすべてのテーブルのインデックスを再構築しました。

EXEC <databasename>..sp_MSforeachtable @command1='DBCC DBREINDEX (''*'')', @replacechar='*'
-- Replace <databasename> with the name of your database

SSMSで同じ動作を確認したい場合は、次のようにプロシージャを実行しました。

SET ARITHABORT OFF
EXEC [dbo].[web_GetMyStuffFool] @UserID=1
SET ARITHABORT ON

これをバイパスする別の方法は、これをコードに追加することです。

MyConnection.Execute "SET ARITHABORT ON"
5
Steve Wright

私は同じ問題に遭遇しましたが、SQLテーブルのインデックスを再構築したとき、それは正常に機能したので、SQLサーバー側でのインデックスの再構築を検討する必要があるかもしれません

2
user5534139

DataAdapterの代わりにDataReaderにしないでください。単一の結果セットがあり、変更をDBにプッシュバックする予定がなく、.NETコードに適用された制約が必要ない場合は、使用しないでください。アダプタ。

編集:

それをDataTableにする必要がある場合は、DataReaderを介してDBからデータをプルし、.NETコードでDataReaderを使用してDataTableにデータを設定できます。それでも、DataSetとDataAdapterに依存するよりも高速です。

1
Marcus King

「なぜ」それ自体が非常に遅いのかはわかりませんが、マーカスが指摘しているように、Mgmt Studioをデータセットの入力と比較すると、リンゴがオレンジになります。データセットには多くのオーバーヘッドが含まれています。私はそれらを嫌い、私がそれを助けることができるならばそれらを決して使用しません。

SQLスタックの古いバージョンなどの不一致に関する問題が発生している可能性があります(espが.NET 1.1でもスタックしていることを考えると、espです)。フレームワークは、スキーマなどを推測するために「Reflection」と同等のデータベースを実行しようとしている可能性があります。

不幸な制約を試すことを検討する1つのことは、データリーダーでデータベースにアクセスし、コードで独自のデータセットを構築することです。あなたはグーグル経由で簡単にサンプルを見つけることができるはずです。

0
fuzzbone