6

まず、背景について説明します。私は SSIS 初心者で、2 つ目のデータ インポート プロジェクトを完了したところです。

パッケージは非常にシンプルで、タブで区切られた ~30,000 レコードの顧客値ファイルを ADO レコードセット変数にインポートするデータフローで構成されています。この変数は、それぞれから値を渡す SQL を実行する ForEach ループ コンテナーを強化するために使用されます。レコードセットの行。

最初の ~21,000 レコードのインポートは、失敗するまでに 59 時間かかりました! 最後の ~9,000 には、さらに 8 時間かかりました。はい、合計67時間!

SQL は、レコードが既に存在するかどうかを判断するためのチェック、新しいパスワードを生成するためのプロシージャへの呼び出し、および顧客データをシステムに挿入するための別のプロシージャへの最後の呼び出しで構成されます。最後の手順はレコードセットを返しますが、私は結果に無関心なので無視しました。SSIS がレコードセットを破棄するかどうかはわかりません。これがデータをシステムに取り込む最も遅い方法であることは承知していますが、これほど遅くなるとは思っていませんでした。また、最後の ~9,000 を処理している間に 3 分の 2 で失敗することもありませんでした。

ローカル マシンで約 3,000 レコードのサブセットをテストしたところ、パッケージ実行ユーティリティは、各挿入に約 1 秒かかっていると報告しました。ちょっとした簡単な計算と提案は、合計インポートの実行に約 8 時間かかるということでした。SSIS と RBAR の実行について読んだことを考えると、長い時間のように思えました。サーバーがかなり強力なので、最終的なインポートは少し速くなると思いました。私はリモートでサーバーにアクセスしていますが、これが問題になるとは思っていませんでした。過去に、シンプルな ADO 接続を使用する特注の C# コンソール アプリケーションを使用してインポートを実行したことがあり、それほど遅く実行されたことはありませんでした。

当初、宛先テーブルは存在チェック用に最適化されていませんでした。これがパフォーマンスの低下の原因である可能性があると考えました。テーブルに適切なインデックスを追加して、テストをスキャンからシークに変更しました。これにより、パフォーマンスの問題が解消されることを期待しています。奇妙なことに、目に見える効果はないように見えました。

システムにデータを挿入するために sproc を使用する理由は、一貫性のためです。これは、データが Web フロントエンドを介してシステムに挿入された場合と同じ経路を表します。また、データの挿入により、多数のトリガーが起動され、データベース内の他のさまざまなエンティティが更新されます。

ただし、このインポート中に発生していて、頭を悩ませているのは、パッケージ実行ユーティリティの出力で報告されている SQL バッチの実行時間が、実行中に対数的に増加していることです。最初は 1 秒未満の実行時間でしたが、インポートの過程で 20 秒を超えて終了し、最終的にインポート パッケージは単純に完全に停止しました。

Google と StackOverflow に感謝しますが、これらの症状を説明するものは何も見つかりませんでした。

うまくいけば、そこにいる誰かがいくつかの手がかりを持っています。

ありがとう

ErikE への返信: (これをコメントに収めることができなかったので、ここに追加しました。)

エリック。あなたのリクエストに応じて、3,000 項目のテスト ファイルをそのペースで実行しながら、データベースに対してプロファイラーを実行しました。

SSIS を使用して、プロファイラーに表示されるコードに目に見える違いを挿入する方法を簡単に理解できなかったので、実行全体でプロファイラーを実行しました。これに関連してオーバーヘッドが発生することはわかっていますが、理論的には、実行中は多かれ少なかれ一貫しているはずです。

アイテムごとの期間は、実行全体でかなり一定のままです。

以下は、トレースからのトリミングされた出力です。ここで行った実行では、最初の 800 が以前に入力されたデータと重複していたため、システムは実質的に何の作業も行っていませんでした (イェーイ インデックス!)。インデックスが役に立たなくなり、システムが実際に新しいデータを挿入するとすぐに、それに応じて時間がジャンプすることがわかりますが、最初の要素と最後の要素の間で、読み取り回数が変化したとしても、それほど変化していないようです。最大の項目です。

----------------------------------------------
| | アイテム | CPU | 読む | 書き込み | 期間 |
----------------------------------------------
| | 0001 | 0 | 29 | 0 | 0 |
| | 0002 | 0 | 32 | 0 | 0 |
| | 0003 | 0 | 27 | 0 | 0 |
|… |
| | 0799 | 0 | 32 | 0 | 0 |
| | 0800 | 78 | 4073 | 40 | 124 |
| | 0801 | 32 | 2122 | 4 | 54 |
| | 0802 | 46 | 2128 | 8 | 174 |
| | 0803 | 46 | 2128 | 8 | 174 |
| | 0804 | 47 | 2131 | 15 | 242 |
|… |
| | 1400 | 16 | 2156 | 1 | 54 |
| | 1401 | 16 | 2167 | 3 | 72 |
| | 1402 | 16 | 2153 | 4 | 84 |
|… |
| | 2997年 | 31 | 2193 | 2 | 72 |
| | 2998年 | 31 | 2195 | 2 | 48 |
| | 2999 | 31 | 2184 | 2 | 35 |
| | 3000 | 31 | 2180 | 2 | 53 |
----------------------------------------------

また、一晩中、システムにインポートを完全に再実行させ、プロファイラーをオンにして、事態がどのように懸念されたかを確認しました。私のローカル マシンでは、15.5 時間でインポートの 3 分の 1 を処理することができました。トレース データを SQL テーブルにエクスポートして、統計情報を取得できるようにしました。トレース内のデータを見ると、挿入間のデルタは、処理された 1,000 レコードごとに最大 1 秒増加するため、レコードが 10,000 に達するまでに、挿入を実行するのにレコードごとに 10 秒かかります。各レコードに対して実行される実際のコードは次のとおりです。わざわざ手順を批判しないでください。SQL は独学の開発者によって書かれました。彼は、実際の開発者教育を受けた人が会社に雇われるずっと前に、もともと私たちの受付係でした。良くないことは十分承知しています。

if not exists
(
    select 1
    from [dbo].[tblSubscriber]
    where strSubscriberEmail = @EmailAddress
    and ProductId = @ProductId
    and strTrialSource = @Source
)
begin
    declare @ThePassword varchar(20)
    select @ThePassword = [dbo].[DefaultPassword]()

    exec [dbo].[MemberLookupTransitionCDS5] 
     @ProductId
    ,@EmailAddress
    ,@ThePassword
    ,NULL --IP Address
    ,NULL --BrowserName
    ,NULL --BrowserVersion
    ,2 --blnUpdate
    ,@FirstName --strFirstName
    ,@Surname --strLastName
    ,@Source --strTrialSource
    ,@Comments --strTrialComments
    ,@Phone --strSubscriberPhone
    ,@TrialType --intTrialType
    ,NULL --Redundant MonitorGroupID
    ,NULL --strTrialFirstPage
    ,NULL --strTrialRefererUrl
    ,30 --intTrialSubscriptionDaysLength
    ,0 --SourceCategoryId
end
GO

各実行間の時間差を決定した結果 (簡潔にするために切り取られています)。

----------------------
| | 行 | 行 | デルタ (ミリ秒) |
----------------------
| | 500 | 510 |
| | 1000 | 976 |
| | 1500 | 1436年 |
| | 2000年 | 1916年 |
| | 2500 | 2336 |
| | 3000 | 2816 |
| | 3500 | 3263 |
| | 4000 | 3726 |
| | 4500 | 4163 |
| | 5000 | 4633 |
| | 5500 | 5223 |
| | 6000 | 5563 |
| | 6500 | 6053 |
| | 7000 | 6510 |
| | 7500 | 6926 |
| | 8000 | 7393 |
| | 8500 | 7846 |
| | 9000 | 8503 |
| | 9500 | 8820 |
| | 10000 | 9296 |
| | 10500 | 9750 |
----------------------
4

1 に答える 1

2

いくつかの手順を実行しましょう。

  1. アドバイス: サーバーの問題かクライアントの問題かを特定します。トレースを実行し、3000 回目と比較して最初の挿入にかかる時間を確認します。SQL ステートメントに、1 回目と 3000 回目の繰り返しの違いを含めます。これは、トレースでフィルター処理できるため、他のイベントがキャプチャされません。ステートメントの補完を避けるようにしてください。バッチまたは RPC 補完を使用してください。

    応答: プロファイラー トレースから記録された CPU、読み取り、および期間は増加していませんが、実際の経過/有効な挿入時間は増加しています。

  2. アドバイス: 上記のパターンが 10,000 回目の挿入まで当てはまると仮定すると (異なる場合はアドバイスしてください)、何らかのブロッキングが発生している可能性があります。ご覧のとおり、テーブル内の行数。次のことをお願いします。

    これで問題が解決しない場合は、質問を新しい情報で更新し、ここにコメントしてください。引き続き最善を尽くします.

于 2012-07-20T07:53:42.070 に答える