web-dev-qa-db-ja.com

データの一括読み込みとトランザクションログ

現在、フラットファイル(csv)からデータを一括インポートするプロジェクトに取り組んでいます。それぞれ約18の異なるファイルが、いくつかのストアドプロシージャを介して特定のテーブルにリンクしています。

データ読み込みパフォーマンスガイド でアドバイスされている手順に従いました。

600000行を含むファイルで以下のストアドプロシージャを実行すると、ログが最小限になるように、データベースはBulkLoggedリカバリモードになり、エラーが発生します。

メッセージ9002、レベル17、状態4、プロシージャSP_Import__DeclarationClearanceHistory_FromCSV、行34
データベースのトランザクションログがいっぱいです。ログの領域を再利用できない理由を確認するには、sys.databasesのlog_reuse_wait_desc列を参照してください

(テスト目的で、インポートを開始する前に完全バックアップを行います)。

log_reuse_wait_desc以下が表示されます。

log_reuse_wait_desc[〜#〜]チェックポイント[〜#〜]。他のすべてのインポートは正常にインポートされます。

これを解決するためのあらゆる情報を歓迎します。

PROCEDURE [dbo].[SP_Import_DeclarationClearanceHistory_FromCSV]
    @FilePath [nvarchar](1000)
AS
BEGIN
    -- Creating a Temproary Table for importing the data from csv file.
    DBCC TRACEON(610)

    CREATE TABLE #DeclarationClearanceHistory
    (
          [ItemID] [int] IDENTITY(1, 1) NOT NULL ,
          [CMSDeclarationID] [bigint] NOT NULL ,
          [StatusCode] [nvarchar](10) NOT NULL ,
          [SubStatus] [nvarchar](10) NULL ,
          [DepartmentCode] [nvarchar](10) NULL ,
          [StartDate] [datetime] NULL ,
          [EndDate] [datetime] NULL ,
          PRIMARY KEY CLUSTERED ( [ItemID] ASC )
            WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
                   IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
                   ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
        )
    ON  [PRIMARY]

    -- Inserting all the from csv to temproary table using BULK INSERT
    EXEC ('BULK INSERT #DeclarationClearanceHistory
    FROM ''' + @FilePath + '''
    WITH ( FIELDTERMINATOR = ''<,>'', ROWTERMINATOR =''\n'', FIRSTROW = 2, KEEPIDENTITY, CODEPAGE = ''ACP'', ORDER = ''ITEMID ASC'' );') ;

    -- By using MERGE statement, inserting the record if not present and updating if exist.
    MERGE dbo.DeclarationClearanceHistory AS TargetTable                            -- Inserting or Updating the table.
        USING #DeclarationClearanceHistory AS SourceTable                           -- Records from the temproary table (records from csv file).
        ON ( TargetTable.ItemID = SourceTable.ItemID )      -- Defining condition to decide which records are alredy present
        WHEN NOT MATCHED BY TARGET 
            THEN INSERT (
                          ItemID ,
                          CMSDeclarationID ,
                          StatusCode ,
                          SubStatus ,
                          DepartmentCode ,
                          StartDate ,
                          EndDate
                        )
               VALUES   ( SourceTable.ItemID ,
                          SourceTable.CMSDeclarationID ,
                          SourceTable.StatusCode ,
                          SourceTable.SubStatus ,
                          SourceTable.DepartmentCode ,
                          SourceTable.StartDate ,
                          SourceTable.EndDate
                        )
        WHEN MATCHED -- If  matched then UPDATE
            THEN UPDATE
               SET      TargetTable.ItemID = SourceTable.ItemID ,
                        TargetTable.CMSDeclarationID = SourceTable.CMSDeclarationID ,
                        TargetTable.StatusCode = SourceTable.StatusCode ,
                        TargetTable.SubStatus = SourceTable.SubStatus ,
                        TargetTable.DepartmentCode = SourceTable.DepartmentCode ,
                        TargetTable.StartDate = SourceTable.StartDate ,
                        TargetTable.EndDate = SourceTable.EndDate ;
DBCC TRACEOFF(610)
END
7
Raymond

最初のコメントは、ETL(抽出、変換、読み込み)ではなくELT(抽出、読み込み、変換)を実行しているということです。 ELTは、セットベースのリレーショナルアドバンテージを活用し、非常に高速になる可能性がありますが、非常に書き込みが集中する場合があります(ストレージ上でハード)。具体的には、tログ。これは、変換がディスク上で行われるためです(通常、更新または挿入)。変換はバッファーで行われ、正しく行われると、最小限のt-log書き込みが必要になるため、可能な場合はETLを使用します。バッファは安いです。高速ストレージではありません。一部の一括操作では、t-logは付加価値のないボトルネックになります。

ここではいくつかのことを行っていますが、お勧めしません。

  1. Tempdbへの一括読み込み。宛先データベースの実際のテーブルで一括読み込みを実行することをお勧めします。次に、それに応じてファイルのサイズを変更でき、tempdbへの影響を心配する必要はありません。
  2. 独立した手順を一緒にバンドルする。これら2つの手順を分割します。バルクロードとマージは互いに独立しています。それらを個別の手順に分割することで、モジュール化/単体テストが可能になります。

最小限のロギングルールが十分にカバーされているようです。クラスター化されていない空のBツリーに、指定された順序キーであるtf 610を使用して、一括ログモードでロードしています。一時テーブルの外では、ここではすべて問題ありません。ファイルが実際にキーで並べ替えられている限り、問題はありません。 tempdbまたはユーザーデータベースのログをポップしますか?

マージステートメント:

更新は常に完全にログに記録されます。テーブルのかなりの部分を変更していますか?その場合は、メモリ(SSISデータフロータスクまたは.Net)でマージしてから、新しいテーブルに一括読み込みすることを検討してください。これはより多くの作業ですが、ほとんどの作業はバッファで行われ、最小限のt-logが使用されます。変更の部分が重要である場合、最小ログ挿入は完全ログ更新よりも高速になる可能性があります。

Tf 610を使用しているため、タブロックヒントを使用すると、挿入で最小限のログを記録できます。 tablockとのマージの詳細については、ここを参照してください: http://blogs.msdn.com/b/sqlserverstorageengine/archive/2010/06/03/minimal-logging-and-merge-statement.aspx このルートに進んでも、更新は完全に記録されます。

4
brian

そのデータベースのlog_reuse_wait_descとしてCHECKPOINTが表示される場合、それは、ログが最後に切り捨てられてからチェックポイントが発生していないためです。

CHECKPOINT コマンドを手動で開始することで、この問題を緩和できます。

サポート参照
ログの切り捨てを遅延させる可能性のある要因
チェックポイントとログのアクティブな部分

4
Thomas Stringer