現在、フラットファイル(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
最初のコメントは、ETL(抽出、変換、読み込み)ではなくELT(抽出、読み込み、変換)を実行しているということです。 ELTは、セットベースのリレーショナルアドバンテージを活用し、非常に高速になる可能性がありますが、非常に書き込みが集中する場合があります(ストレージ上でハード)。具体的には、tログ。これは、変換がディスク上で行われるためです(通常、更新または挿入)。変換はバッファーで行われ、正しく行われると、最小限のt-log書き込みが必要になるため、可能な場合はETLを使用します。バッファは安いです。高速ストレージではありません。一部の一括操作では、t-logは付加価値のないボトルネックになります。
ここではいくつかのことを行っていますが、お勧めしません。
最小限のロギングルールが十分にカバーされているようです。クラスター化されていない空の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 このルートに進んでも、更新は完全に記録されます。
そのデータベースのlog_reuse_wait_descとしてCHECKPOINT
が表示される場合、それは、ログが最後に切り捨てられてからチェックポイントが発生していないためです。
CHECKPOINT
コマンドを手動で開始することで、この問題を緩和できます。