HN 日本語サマリー

← 一覧へ戻る
プログラミング

SQL Serverバックアップ(.bak)からリストアせずにテーブルをParquetにエクスポートする

Exporting tables from a SQL Server backup (.bak) to Parquet without restoring it (blog.arpe.io)

10 pointsby rferraton1 コメント

要約

FastBCP 1.6は、SQL Serverのフルバックアップファイルから直接テーブルをParquet形式にエクスポートできるツールです。リストアやSQL Serverインスタンスのセットアップが不要で、大規模なバックアップでも高速に処理できます。この機能は、テーブルの復旧、移行、データウェアハウスへのロードなど、様々なユースケースで活用できます。

全文翻訳

FastBCP 1.6: SQL Serverバックアップからテーブルをエクスポート

TL;DR

FastBCP 1.6は、リストアやSQL Serverインスタンスなしで、SQL ServerのフルバックアップからテーブルをParquetにエクスポートします。320 GBのプロダクションバックアップでは、最初のオープンに2分29秒、それ以降は0.3秒でした。24スレッドを使用すると、1億7500万行のテーブルが29.6秒でParquetに変換されました。FastTransferは、これらのファイルをSQL Server(どのバージョンでも)またはPostgreSQLにロードできます。

FastBCP 1.6は、SQL Serverのフルバックアップから直接テーブルを読み取ります。.bakファイルとテーブル名を指定するだけで、Parquetファイルが得られます。リストアも、SQL Serverインスタンスも、管理すべき認証情報も不要です。

現時点ではParquetのみが出力形式です。しかし、これでループは閉じます。FastTransferは、これらのファイルを任意のSQL Serverインスタンスにロードでき、そのインスタンスはバックアップが作成されたバージョンよりも古いバージョンで実行することも可能です。RESTOREではこれができません。

初めてのエクスポート​

新しい接続タイプはbackup_mssqlです。

  • --server はバックアップが格納されているディレクトリです。

  • --database はバックアップファイル、またはそれに一致するパターンです(ストライプバックアップの場合は tpch_*.bak)。ストライプは ; で区切ってリストすることもできます。

  • Windows

  • Linux

.\FastBCP.exe `  --connectiontype backup_mssql `  --server "D:\Backups\MSSQL" `  --database "tpch_full.bak" `  --sourceschema "dbo" `  --sourcetable "orders" `  --directory "D:\export\orders" `  --fileoutput "orders.parquet" `  --parallelmethod Physical `  --paralleldegree 8

バックアップをソースとして使用する場合、--parallelmethod Physical はテーブルを --paralleldegree の数だけスライスします。各スレッドは独自の Слайс を読み取り、チャンクごとに1つのファイルが得られます(orders_chunk_000.parquet, orders_chunk_001.parquet…)。

列のサブセットをエクスポートするには、--query と列リストを使用します: SELECT o_orderkey, o_orderdate FROM dbo.orders。これは完全な構文で、SELECT * | col1, col2, … FROM [schema.]table となります。WHERE 句は受け付けられません。

ファイルは次にここに送られます:

読み取るもの​

backup_mssql の背後にあるドライバである ArpeMSBackup は、SQL Serverコンポーネントを一切使用せずに、バックアップファイルを独自に読み取ります。

SQL Serverのバージョン

  • 2017
  • 2019
  • 2022
  • 2025

バックアップの種類

  • フル
  • コピーオンリーフル
  • 1つのファイルに複数のバックアップ

バックアップ圧縮

  • なし
  • MS_XPRESS
  • ZSTD
  • 任意のブロックサイズ

ストライプバックアップ

  • パターン
  • リスト
  • 任意の順序

データベースレイアウト

  • 複数のデータファイル
  • 複数のファイルグループ

行ストアテーブル

  • ヒープ
  • クラスター化インデックス
  • パーティション
  • データ圧縮

列ストアテーブル

  • クラスター化列ストア
  • アーカイブ圧縮
  • オープンデルタストア
  • 削除された行
データ型​

bigint✓
int✓
smallint✓
tinyint✓
bit✓
decimal✓
numeric✓
money✓
smallmoney✓
float✓
real✓
date✓
time✓
datetime✓
datetime2✓
smalldatetime✓
datetimeoffset✓
char✓
varchar✓
varchar(max)✓
nchar✓
nvarchar✓
nvarchar(max)✓
text✓
ntext✓
binary✓
varbinary✓
varbinary(max)✓
image✓
uniqueidentifier✓
rowversion✓
xml✓
sql_variant✓
hierarchyid✓
geography✓
geometry✓
vector(n)✓
vector(n, float16)✗
json✗

完全なマッピングは データ型変換ページ にあります。

制限事項​

フルバックアップのみ

コピーオンリーは含まれます。差分バックアップとログバックアップは適用されません。フルバックアップを含まないファイルは拒否されます。

暗号化なし

TDEデータベースのバックアップと暗号化されたバックアップ(WITH ENCRYPTION)は拒否されます。サーバー証明書なしではページを読み取ることができません。

QAT_DEFLATEなし

Intel QuickAssistで圧縮されたバックアップはサポートされていません。MS_XPRESSとZSTDはサポートされています。

Parquet出力のみ

Windows x64およびLinux x64で利用可能です。

もう一つ注意点として、RESTOREはバックアップに含まれるトランザクションログの一部を再生してデータベースを整合させます。FastBCPはそうしません。バックアップ実行中にテーブルに書き込みが行われていた場合、その時点でのページが得られます。正確なイメージを得るには、テーブルが静止している間にバックアップを取得してください。

ユースケース​

n個のテーブルをリストアする​

テーブルが削除された、または火曜日のバージョンが必要な場合。通常の解決策は、データベース全体を本番環境の隣にリストアすることですが、これはデータベースと同等の空きディスク容量と、1つのテーブルを取り戻すために数時間かかるリストアを意味します。

FastBCPとFastTransferを使用すると、バックアップからその1つのテーブルをエクスポートし、任意の場所にロードできます。スクラッチデータベース、別の名前で本番サーバー、または古いバージョンのインスタンスなどです。SQL Serverは、作成したバージョンよりも古いバージョンにバックアップをリストアできませんが、Parquetファイルは気にする必要がありません。

ロードステップではFastTransferを使用し、Parquetファイルごとに1つのチャンクを使用します。ターゲットテーブルは存在している必要があります。

  • Windows
  • Linux
.\FastTransfer.exe `  --sourceconnectiontype duckdbstream `  --sourceserver ":memory:" `  --query "SELECT * EXCLUDE filename FROM read_parquet('D:\export\orders\*.parquet', filename=true)" `  --targetconnectiontype msbulk `  --targetserver "sql2019\restore" `  --targetdatabase "tpch_restore" `  --targettrusted `  --targetschema "dbo" `  --targettable "orders" `  --loadmode Truncate `  --mapmethod Name `  --parallelmethod DataDriven `  --distributekeycolumn "filename" `  --datadrivenquery "SELECT file FROM glob('D:\export\orders\*.parquet')" `  --degree 8
マイグレーション​

マイグレーションは、既存データのバルクコピーから始まります。昨夜のフルバックアップからデータを読み取ることで、ソースサーバーへの負荷がかからず、バックアップはしばしばマイグレーションチームがアクセスできる共有フォルダに既に存在します。新しいバージョンから古いバージョンへのパスにとどまる必要がある場合でも、Parquetはバージョン制約を排除します。

例えば、SQL ServerからPostgreSQLに移行する場合を考えてみましょう。FastBCPはバックアップから各テーブルをParquetにエクスポートし、その後FastTransferがPostgreSQLのCOPYプロトコルを通じてファイルをロードします。

このコマンドペアをテーブルごとに1回実行します。まずターゲットテーブルを作成してください: FastTransferは既存のテーブルにロードします。

  • Windows
  • Linux
.\FastBCP.exe `  --connectiontype backup_mssql `  --server "D:\Backups\MSSQL" `  --database "tpch_full.bak" `  --sourceschema "dbo" `  --sourcetable "orders" `  --directory "D:\export\orders" `  --fileoutput "orders.parquet" `  --parallelmethod Physical `  --paralleldegree 8.
FastTransfer.exe `  --sourceconnectiontype duckdbstream `  --sourceserver ":memory:" `  --query "SELECT * EXCLUDE filename FROM read_parquet('D:\export\orders\*.parquet', filename=true)" `  --targetconnectiontype pgcopy `  --targetserver "pgserver:5432" `  --targetdatabase "tpch" `  --targetuser "FastUser" `  --targetpassword "FastPassword" `  --targetschema "public" `  --targettable "orders" `  --loadmode Truncate `  --mapmethod Name `  --parallelmethod DataDriven `  --distributekeycolumn "filename" `  --datadrivenquery "SELECT file FROM glob('D:\export\orders\*.parquet')" `  --degree 8

最終的なカットオーバーも同じパスを使用できます。アプリケーションを停止し、COPY_ONLYフルバックアップを取得し、エクスポートしてロードします。アプリケーションが停止している間は、バックアップは整合しており、ログの再生は不要です。直接転送よりも優れているかどうかは、データベースのサイズとカットオーバーウィンドウに依存するため、両方を測定してください。

データウェアハウスまたはデータレイクへの供給​

ほとんどのプロダクションデータベースは毎晩バックアップされており、それらのバックアップは既にプロダクションの外のどこかに配置されています。FastBCPは、プロダクションへの接続を一切開くことなく、それらをデータレイクやウェアハウスロード用のParquetファイルに変換できます。リードレプリカも、抽出ウィンドウも、ビジーなテーブルへのリードロックも不要です。

なぜ高速なのか​

直接テーブルへ​

ドライバはバックアップをプレーンなバイナリファイルとして読み取ります。要求されたテーブルのデータに直接アクセスし、ファイル内の他のすべてをスキップするのに十分な理解を持っています。値はApache Arrowカラムに直接デコードされ、FastBCPはそれをParquetに書き込みます。

バックアップからの最初のエクスポートは、一度限りのコストがかかります。ファイル全体が一度読み取られ、必要に応じて解凍され、ドライバがその中での位置を把握できるようにします。FastBCPは、学習した内容を小さなローカルキャッシュに保持します。同じバックアップからの後続のエクスポート(どのテーブルであっても)はこのステップをスキップします。以下の320 GBのプロダクションバックアップで測定したところ、最初のオープンに2分29秒かかりましたが、それ以降は0.3秒でした。新しいバックアップファイルは、新たに読み取られます。

必要に応じた並列読み取り​

--parallelmethod Physical を使用すると、各スレッドがテーブルの共有部分を担当します。すべてのスレッドは同じ開かれたバックアップを操作するため、並列度に関係なく一度だけ開かれます。圧縮バックアップの場合、解凍されたデータも共有されます。

ロック、ラッチなし​

ロックマネージャー、バッファラッチ、他のセッション、SQL Serverプロセスはありません。スレッドはページを読み取り、何も待機しません。プロダクションサーバーはエクスポートを一切認識しません。

メモリ使用量はバックアップサイズに依存しない​

バックアップはインプレースで読み取られ、メモリにロードされることはありません。データはファイルからArrowバッチに一度だけ流れます。メモリに残るのは、少量のメタデータ、スレッドごとの1つのバッチ、および圧縮バックアップの場合は共有の解凍キャッシュ(デフォルトで256 MB)です。1500万行の行ストアテーブルを8スレッドでエクスポートした場合、非圧縮バックアップではFastBCPプロセス全体で最大674 MB、ZSTDバックアップでは979 MBでした。

列ストアテーブルは例外であり、現在の弱点です。最大100万行の行グループがまとめてデコードされるため、メモリはスレッド数と列数に応じて増加します。以下の実際のテーブルでは、24スレッドで62列の場合は26 GB、124列の場合は44 GBがピークでしたが、同じテーブルのライブエクスポートは4.5 GBに留まりました。現在対応中です。それまでは、メモリの少ないマシンでは --paralleldegree を低く設定してください。

更新: FastBCP 1.6.5

FastBCP 1.6.5は、列ストアテーブルのメモリ使用量を制限します。このバージョン以前では、8スレッドで幅の広いクラスター化列ストアテーブルをエクスポートした場合のピークメモリは42 GBでしたが、このバージョンでは5.9 GBにピークメモリが抑えられます。この記事の数値は1.6.3および1.6.4で測定されたものです。リリースノートを参照してください。

info

速度は2つの要因に依存します。ディスクの読み取り速度と、エクスポートツールのデコードおよび書き込み速度です。ローカルNVMeドライブは数GB/秒、まともなSSDは数百MB/秒を提供します。USBメモリや、スループットがサイズに依存する小さなクラウドディスクはボトルネックになります。良好なディスクでは、制限はエクスポートツールであり、FastBCPはまさにその部分のために構築されています。

パフォーマンス​

実際の列ストアテーブル、FastBCP 1.6.3​

これらの実行は、ベンチマークスキーマではなく、実際のプロダクションデータベースからのものです。2つのクラスター化列ストアテーブルがあり、1つは62列、もう1つは124列で、どちらも1億行を超えています。ソースは、そのデータベースの夜間フルバックアップです。383テーブル、320 GBが16個の20 GBファイルにストライプされています。サーバーは、Windows Server 2022上の128論理プロセッサと1 TBのRAMを搭載したIntel Xeon Gold 6430マシンです。

すべての実行は、FastBCP 1.6.3が24スレッドでZstd Parquetに書き込むものです。バックアップに対しては--parallelmethod Physical、SQL Server 2022インスタンスからのライブエクスポート(同じデータベースを保持)に対してはadbc_mssql経由で--parallelmethod Ntileを使用します。最初のバックアップ実行はコールドランで、このバックアップが初めて開かれたときです。2回目はバックアップがキャッシュ内にある場合です。

FastBCP 1.6.3、24スレッドによるエクスポート(実際の列ストアテーブル)

実行

行 × 列

オープン

合計時間

行/秒

セル/秒

ピークメモリ

バックアップ、コールド、テーブルA

175.1 M × 62

148.6 s

179.1 s

0.98 M

61 M

26.2 GB

バックアップ、ウォーム、テーブルB

220.9 M × 124

0.3 s

71.8 s

3.07 M

381 M

43.6 GB

ライブ adbc_mssql、テーブルB

220.9 M × 124

–

155.9 s

1.42 M

176 M

4.5 GB

コールド vs ウォームバックアップ、エクスポート速度(セル/秒)

高いほど良い

  • コールド: バックアップの最初のオープン
  • ウォーム: バックアップが一度開かれたことがある

コールド: 最初のオープン + エクスポート、テーブルA60.6 M

コールド: エクスポートのみ、テーブルA366.4 M

ウォーム: キャッシュされたオープン + エクスポート、テーブルB381.3 M

バックアップ vs ライブデータベース、同じ124列テーブル(セル/秒)

高いほど良い

  • バックアップ、backup_mssql (ウォーム)
  • ライブ、SQL Server 2022上のadbc_mssql

バックアップ、ウォーム381.3 M

ライブデータベース175.7 M

  • 同じ124列テーブルで、バックアップエクスポートは72秒、ライブエクスポートは156秒かかりました。これは2.2倍高速で、SQL Serverは何も作業しませんでした。
  • コールドオープンは320 GBのバックアップ全体で一度、2分29秒かかりました。これはディスクから約2.2 GB/秒の読み取り速度です。その後、1億7500万行のテーブルAは29.6秒でParquetに変換されました。これは毎秒5.9 M行、または毎秒3.66億セルです。このバックアップからの後続のエクスポートはすべて0.3秒で開始します。
  • 幅の広いテーブルでは、セル/秒が行/秒よりも多くの情報を提供します。テーブルBでは、毎秒3億8100万の値がデコードおよび書き込まれました。
  • 1.6.3ではメモリが問題でした。ピーク時44 GBに対し、ライブエクスポートでは4.5 GBでした。FastBCP 1.6.5ではこれが削減されています。メモリ使用量はバックアップサイズに依存しないを参照してください。
TPC-H SF10をラップトップで実行​

これらの数値は私のラップトップで実行しました。Intel i9-13950HX(8つのパフォーマンスコア、16の効率コア)、64 GBのRAM、1つのNVMe SSD、Windows 11です。テストデータベースはTPC-H形状で、6000万行のlineitemテーブル(16列)1つと、ストレージのみが異なる1500万行のordersテーブル3つ(9列)があります。3回バックアップしました。非圧縮(9.9 GB)、ZSTD(5.7 GB)、MS_XPRESS(3.8 GB)です。

各実行は、FastBCP 1.6.4が--parallelmethod Physical --paralleldegree 8でParquetに書き込むものです。各テーブルと各バックアップについて、まずコールドランを実行します。ドライバのキャッシュがクリアされるため、エクスポートはバックアップを初めて開きます。その後、3回のウォームランが続き、テーブルの中央値を示します。比較のために、同じテーブルをローカルのSQL Server 2025インスタンス上のライブデータベースから、adbc_mssql(ArpeMSSQLドライバ)とmssql(SqlClient)経由でエクスポートします。数値はセル/秒(行 × 列)、FastBCPプロセス全体の壁時計時間です。

ウォームラン: million cells/secでのFastBCP 1.6.4によるエクスポート速度(TPC-H SF10 db)

テーブル

ストレージ

非圧縮バックアップ

ZSTDバックアップ

MS_XPRESSバックアップ

ライブ、adbc_mssql

ライブ、mssql

orders_ci

クラスター化インデックス

88.8 M

84.4 M

78.0 M

37.9 M

15.9 M

orders_page

クラスター化、PAGE圧縮

83.3 M

81.3 M

66.8 M

35.7 M

15.4 M

orders_heap

ヒープ

83.3 M

81.8 M

75.4 M

34.8 M

14.4 M

lineitem_cci

クラスター化列ストア

148.8 M

149.8 M

145.5 M

52.6 M

23.8 M

コールドラン: キャッシュクリア後の最初のエクスポート、million cells/sec(オープン時間)

テーブル

非圧縮バックアップ

ZSTDバックアップ

MS_XPRESSバックアップ

orders_ci

66.5 M (0.6 s)

25.7 M (3.6 s)

27.6 M (3.1 s)

orders_page

60.3 M (0.6 s)

42.7 M (1.5 s)

37.8 M (1.6 s)

orders_heap

61.4 M (0.6 s)

40.2 M (1.6 s)

39.0 M (1.7 s)

lineitem_cci

124.2 M (0.7 s)

119.3 M (1.5 s)

116.9 M (1.6 s)

orders_ci (1500万行 × 9列)、コールド vs ウォーム(セル/秒)

高いほど良い

  • コールド: バックアップの最初のオープン
  • ウォーム: バックアップが一度開かれたことがある
  • ライブデータベース

非圧縮バックアップ、コールド66.5 M

非圧縮バックアップ、ウォーム88.8 M

ZSTDバックアップ、コールド25.7 M

ZSTDバックアップ、ウォーム84.4 M

MS_XPRESSバックアップ、コールド27.6 M

MS_XPRESSバックアップ、ウォーム78.0 M

ライブ、adbc_mssql37.9 M

ライブ、mssql15.9 M

lineitem_cci (6000万行 × 16列)、コールド vs ウォーム(セル/秒)

高いほど良い

  • コールド: バックアップの最初のオープン
  • ウォーム: バックアップが一度開かれたことがある
  • ライブデータベース

非圧縮バックアップ、コールド124.2 M

非圧縮バックアップ、ウォーム148.8 M

ZSTDバックアップ、コールド119.3 M

ZSTDバックアップ、ウォーム149.8 M

MS_XPRESSバックアップ、コールド116.9 M

MS_XPRESSバックアップ、ウォーム145.5 M

ライブ、adbc_mssql52.6 M

ライブ、mssql23.8 M

  • ウォーム状態では、ordersテーブル(1500万行、1億3500万セル)は、いずれのバックアップ形式からでも1.5〜2秒でParquetに変換されます。非圧縮バックアップからの場合、ライブadbc_mssqlソースの2.3〜2.4倍、mssqlの5.4〜5.8倍です。
  • 列ストアは、バックアップ形式に関係なく約1億4900万セル/秒に達します。これは、6000万行を6.4秒で処理し、adbc_mssqlの2.8倍、mssqlの6.3倍です。
  • バックアップが開かれると、圧縮によるコストはわずかです。ZSTDは非圧縮バックアップの5%以内、MS_XPRESSは2〜20%以内に収まります。
  • コールドランはバックアップごとに一度オープンコストを支払います。非圧縮バックアップでは0.6秒、圧縮バックアップでは約1.5秒です。orders_ciは各圧縮バックアップから最初に読み取られたテーブルだったため、そのコールドランでもディスクからファイルを読み取り、3.1〜3.6秒かかりました。その後、同じバックアップのどのテーブルも20〜30ミリ秒でオープンされます。
  • ライブの数値にはSQL Serverの作業が含まれており、同じラップトップで実行されました。バックアップ実行はサーバーに一切触れていません。

3つのバックアップはラップトップの64 GBメモリに収まるため、最初の読み取りを除き、コールドランはディスクではなくドライバによるオープンを測定します。メモリよりもはるかに大きいバックアップの場合、オープンはディスクによって制限されます。これは上記の320 GBバックアップの場合と同様です。

リソース​