2

基本的にあるテーブルから別のテーブルに値をコピーする変換ユーティリティがあります。しばらくは問題なく機能していましたが、ある顧客で奇妙な問題に遭遇しました。彼らはユーティリティで 150 万件のレコードを処理しましたが、現在は完全に停止しています。

VB.Net からストアド プロシージャを呼び出すと、SqlCommand がタイムアウトするまでハングします。Management Studio から同じ sproc を呼び出すと、即座に実行されます。SqlCommand の私の VB.Net コードは次のとおりです (insertConn以前に定義されて開かdrれており、完全に異なる SqlConnection および SqlCommand インスタンスから前の手順で設定された SqlDataReader です):

Dim conn As New SqlConnection("connection string here")
Dim insertConn As New SqlConnection("connection string here")
Dim dr As SqlDataReader = Nothing
Dim readCommand As New SqlCommand("my query here", conn)
conn.Open()
insertConn.Open()
...
dr = readCommand.ExecuteReader()
...
While dr.Read()
    Using insertCommand = New SqlCommand("dmDocumentFieldInsert", insertConn)
        insertCommand.CommandType = CommandType.StoredProcedure

        insertCommand.Parameters.AddWithValue("@DocumentKey", dr("DocumentKey"))
        insertCommand.Parameters.AddWithValue("@FieldId", "TITLE")
        insertCommand.Parameters.AddWithValue("@FieldValue", dr("DocumentTitle"))
        insertCommand.ExecuteNonQuery()
    End Using
End While

SQL Server を再起動してロックをクリアし、sproc を再コンパイルし、SqlCommand と SqlConnection のタイムアウトをすべて無駄に増やしてみました。

パラメータに追加されるデータを確認しましたが、それは有効なデータです...同じデータでsprocを手動で呼び出すと、正常に動作します。

私はもともとUsingブロックを使用していませんでしたが、それを変更して、破棄/クローズされていないリソースの問題があるかどうかを確認しました。ユーティリティのメモリ使用量は約 5MB で推移しているため、メモリの問題はないようです。

解決策として次に何を試すべきかについて提案がある人はいますか?

EDITコメントリクエストごとにループと初期化コードを追加

編集統計を更新し、テーブルのインデックスを再構築しましたが、変更はありません。

EDITデータがコピーされるテーブルには 3 つのインデックスがあります (dmDocumentField)。3 つのインデックスをすべて無効にすると、sproc は完全に実行されますが、インデックスが存在する場合よりもはるかに遅くなります。それらのいずれかを有効にすると、ユーティリティは最大で数百のレコードを通過し、sproc で同じタイムアウトで終了します。インデックスを削除して再作成しても効果はありません。テーブル構造とインデックスは次のとおりです。

CREATE TABLE [dbo].[dmDocumentField](
[FieldKey] [bigint] IDENTITY(1,1) NOT NULL,
[DocumentKey] [char](36) NOT NULL,
[FieldId] [varchar](10) NOT NULL,
[FieldValue] [varchar](255) NOT NULL,
CONSTRAINT [PK_dmDocumentField] PRIMARY KEY NONCLUSTERED 
(
[FieldKey] ASC,
[DocumentKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

インデックス (PK 以外):

CREATE NONCLUSTERED INDEX [dmDocumentField_DocumentKey] ON [dbo].[dmDocumentField]
(
[DocumentKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

.

CREATE NONCLUSTERED INDEX [dmDocumentField_DocumentKey_IFieldId_IFieldValue] ON [dbo].[dmDocumentField]
(
[DocumentKey] ASC
)
INCLUDE (   [FieldId],
[FieldValue]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
4

3 に答える 3

1

私はこれを試します:

... 
dr = readCommand.ExecuteReader() 
... 
insertCommand = New SqlCommand("dmDocumentFieldInsert", insertConn) 
insertCommand.CommandType = CommandType.StoredProcedure 
insertCommand.Parameters.AddWithValue("@DocumentKey", string.Empty)) 
insertCommand.Parameters.AddWithValue("@FieldId", "TITLE") 
insertCommand.Parameters.AddWithValue("@FieldValue", string.Empty)) 

Dim tr As SqlTransaction
tr = insertConn.BeginTransaction
insertCommand.Transaction = tr
While dr.Read() 
        insertCommand.Parameters("@DocumentKey").Value = dr("DocumentKey") 
        insertCommand.Parameters("@FieldValue").Value = dr("DocumentTitle")
        insertCommand.ExecuteNonQuery() 
End While 

tr.Commit()

これはおそらくメモリ集約型ではなく (コマンドの作成、パラメーターの作成がループ内で繰り返されます)、150 万件のレコードがあれば違いが生じる可能性があります。
@DocumentKey と @FieldValue の実際のデータ型はわかりませんが、文字列であると想定されますが、そうでない場合は、適切なダミー値で初期設定を変更してください。

于 2012-06-14T19:43:36.983 に答える
0

これはある特定の顧客にとって 1 回限りの問題だったので、これともう少し戦った後、手作業で変換を行いました。SqlCommand がタイムアウトしたのに SSMS がタイムアウトしなかった理由を知りたいのですが、この時点で完了です。

于 2012-06-15T20:38:09.327 に答える
0

コマンドは、DataReader が選択したのと同じテーブルに対して操作を実行しますか? 同様の状況で、リーダーを実行するようなことをしていました

SELECT ID, Name FROM Table 1

そして、タイムアウトしていた私のコマンドは、DR レコードをループして、次のようなことをしていました。

UPDATE Table1 SET Name = 'foo' WHERE ID = 1

ストレージに DataReader ではなく DataTable を使用するように SELECT を変更すると、SSMS の場合と同様にすぐに機能しました。

于 2012-11-30T00:20:28.517 に答える