web-dev-qa-db-ja.com

mysqldumpを使用して、行ごとに1つの挿入をフォーマットしますか?

これは数回尋ねられましたが、問題の解決策が見つかりません。基本的に、MySQL Workbench管理ツールの組み込みツールであるmysqldumpを使用する場合、拡張挿入を使用してデータベースをダンプすると、大量の長い行のデータが得られます。データを1つのコマンドとして挿入することにより(特にInnoDBで)挿入を高速化するため、これを行う理由を理解していますが、フォーマットにより、実際にダンプファイル内のデータを確認したり、diffツールで2つのファイルを比較したりすることは非常に困難ですバージョン管理などに保存している場合。私の場合、ダンプファイルを使用して統合テストデータベースを追跡するため、バージョン管理に保存しています。

これで、拡張挿入をオフにできることがわかったので、行ごとに1つの挿入を取得しますが、これは機能しますが、ダンプファイルを使用して復元を行うと、遅くなります。

私の中心的な問題は、ファイルをダンプするときに使用するOLDツール(MySQL管理者)で、基本的に同じことを行いますが、一括挿入を実行しながら、INSERTステートメントを1行に1つ挿入するようにフォーマットすることです。したがって、これの代わりに:

INSERT INTO `coupon_gv_customer` (`customer_id`,`amount`) VALUES (887,'0.0000'),191607,'1.0300');

あなたはこれを得る:

INSERT INTO `coupon_gv_customer` (`customer_id`,`amount`) VALUES 
 (887,'0.0000'),
 (191607,'1.0300');

どんなオプションを試しても、このようなダンプを取得する方法はないようです。これは、両方の世界で最高です。はい、もう少しスペースが必要ですが、ファイルを読むために人間が必要な状況では、非常に便利になります。

私は何かを見逃していて、MySQLDumpでこれを行う方法がありますか、それとも私たちはすべて後退し、古い(現在廃止されている)MySQL Administratorツールのこの機能はもう利用できませんか?

45
Kendall Bennett

デフォルトのmysqldump形式では、ダンプされた各レコードは、ダンプファイル(つまり、sqlファイル)に個別のINSERTコマンドを生成し、それぞれが独自の行になります。これはソース管理(svn、gitなど)に最適です。差分とデルタの解像度がより細かくなり、最終的にはより効率的なソース管理プロセスになります。ただし、サイズが非常に大きいテーブルの場合、これらのINSERTクエリをすべて実行すると、sqlファイルからの復元が非常に遅くなる可能性があります。

--extended-insertオプションを使用すると、ダンプされたsqlファイルの1行ですべてのレコードを1つのINSERTコマンドにラップすることにより、複数のINSERT問題が修正されます。ただし、ソース管理プロセスは非常に非効率的になります。テーブルの内容全体がsqlファイルの1行で表されます。1文字がそのテーブルのどこかで変更されると、ソース管理は行全体(つまりテーブル全体)にバージョン間のデルタとしてフラグを立てます。また、大きなテーブルの場合、これは正式なソース管理システムを使用する利点の多くを無効にします。

したがって、理想的には、データベースを効率的に復元するために、sqlファイルで、各テーブルを単一のINSERTで表すようにします。効率的なソース管理プロセスのために、sqlファイルでは、そのINSERTコマンドの各レコードを独自の行に配置する必要があります。

これに対する私の解決策は、次のバックアップスクリプトです。

#!/bin/bash

cd my_git_directory/

ARGS="--Host=myhostname --user=myusername --password=mypassword --opt --skip-dump-date"
/usr/bin/mysqldump $ARGS --database mydatabase | sed 's$VALUES ($VALUES\n($g' | sed 's$),($),\n($g' > mydatabase.sql

git fetch Origin master
git merge Origin/master
git add mydatabase.sql
git commit -m "Daily backup."
git Push Origin master

結果は、次のようなsqlファイルのINSERTコマンド形式です。

INSERT INTO `mytable` VALUES
(r1c1value, r1c2value, r1c3value),
(r2c1value, r2c2value, r2c3value),
(r3c1value, r3c2value, r3c3value);

いくつかのメモ:

  • コマンドラインでのパスワード...私は知っている、安全ではない、別の議論。
  • --opt:特に、--extended-insertオプションをオンにします(つまり、テーブルごとに1つのINSERT)。
  • --skip-dump-date:mysqldumpは通常、作成時にsqlファイルに日付/時刻スタンプを付けます。バージョン間の唯一のデルタがその日付/時刻スタンプである場合、これはソース管理で迷惑になることがあります。 OSおよびソース管理システムは、ファイルとバージョンに日付/時刻をスタンプします。 sqlファイルでは必要ありません。
  • Gitコマンドは基本的な質問(sqlファイルのフォーマット)の中心ではありませんが、svnを使用してsqlファイルをソース管理に戻す方法を示しています。このsqlファイル形式を選択したソース管理と組み合わせると、ユーザーが作業コピーを更新するときに、インターネット上でデルタ(つまり、変更されたレコード)を移動するだけで、diffユーティリティを利用できることがわかります。データベース内のどのレコードが変更されたかを簡単に確認できます。
  • リモートサーバーにあるデータベースをダンプする場合は、可能であれば、そのサーバーでこのスクリプトを実行して、ダンプごとにデータベースの内容全体をネットワークにプッシュしないようにします。
  • 可能であれば、このスクリプトを実行しているサーバーと同じサーバー上で、SQLファイル用の作業用ソース管理リポジトリを確立します。そこからリポジトリにチェックインします。また、これにより、ダンプごとにデータベース全体をネットワーク経由でプッシュする必要がなくなります。
30
Todd Blumer

次のオプションを使用してみてください。-skip-extended-insert

それは私のために働いた。

34
Eric Tan

他の人がsedを使用して ")、("を置き換えると言ったように、これはデータベースのコンテンツとして表示される可能性があるため安全ではありません。ただし、これを行う方法があります。

$ mysqldump -u my_db_user -p -h 127.0.0.1 --skip-extended-insert my_database > my_database.sql
$ sed ':a;N;$!ba;s/)\;\nINSERT INTO `[A-Za-z0-9$_]*` VALUES /),\n/g' my_database.sql > my_database2.sql

「sed -i」を使用してインラインを置き換えることもできます。

このコードの動作は次のとおりです。

  1. --skip-extended-insertは、行ごとに1つのINSERT INTOを作成します。
  2. 次に、sedを使用してデータをクリーンアップします。 sedを使用した通常の検索/置換は単一行に適用されるため、sedは一度に1行ずつ動作するため、「\ n」文字を検出できないことに注意してください。そのため、「:a; N; $!ba;」と入力します。これは基本的にsedに複数行を検索して次の行をバッファするように指示します。

お役に立てれば

11
Ace.Di

このような--tabオプションを使用して、mysqldumpでCSVファイルにダンプを保存するのはどうですか?

mysqldump --tab=/path/to/serverlocaldir --single-transaction <database> table_a

これにより、2つのファイルが生成されます。

  • table_a.sqlテーブル作成ステートメントのみを含む;そして
  • table_a.txtはタブ区切りデータを含みます。

復元中

LOAD DATAでテーブルを復元できます:

LOAD DATA INFILE '/path/to/serverlocaldir/table_a.txt' 
  INTO TABLE table_a FIELDS TERMINATED BY '\t' ...

LOAD DATAは通常、INSERTステートメントを使用するよりも20倍高速です。

データを別のテーブルに復元する必要がある場合(たとえば、レビューやテストの目的で)、「ミラー」テーブルを作成できます。

CREATE TABLE table_for_test LIKE table_a;

次に、CSVを新しいテーブルにロードします。

LOAD DATA INFILE '/path/to/serverlocaldir/table_a.txt' 
  INTO TABLE table_for_test FIELDS TERMINATED BY '\t' ...

比較する

CSVファイルは、差分や内部を見るため、またはExcelAccessまたはコマンドライン(diffcommなど...)

8
Cristian Porta

これは不可能だと思います。古いMySQL管理者で、dbオブジェクトをダンプするためのコードを作成しました。このコードは、mysqldumpツールとは完全に独立しており、そのため多くの追加オプション(このフォーマットや進捗フィードバックなど)を提供しました。 MySQL Workbenchでは、代わりにmysqldumpツールを使用することに決定しました。これは、いくつかの点で後退し、バージョンの問題を引き起こすことに加えて、常にサーバーを最新の状態に保つ利点があります。

簡単な答えは次のとおりです。現在、mysqldumpではフォーマットが不可能です。

5
Mike Lischke

このツールは、拡張挿入の処理に非常に役立つことがわかりました。 http://blog.lavoie.sl/2014/06/split-mysqldump-extended-inserts.html

Mysqldump出力を解析し、各レコードの後に​​改行を挿入しますが、それでも高速の拡張挿入を使用します。 sedスクリプトとは異なり、文字列内で正規表現が一致した場合、間違った場所で行を壊す危険はありません。

1
seanf

これを試して:

mysqldump -c -t --add-drop-table=FALSE --skip-extended-insert -uroot -p<Password> databaseName tableName >c:\path\nameDumpFile.sql
0

このエラーが発生するまで、私はsedを使用したAce.Diのソリューションが好きでした:sed:メモリを再割り当てできませんでした

したがって、小さなPHPスクリプトを書かなければなりませんでした

mysqldump -u my_db_user -p -h 127.0.0.1 --skip-extended-insert my_database | php mysqlconcatinserts.php > db.sql

PHPスクリプトは、メモリの問題を回避するために、10.000行ごとに新しいINSERTも生成します。

mysqlconcatinserts.php:

#!/usr/bin/php
<?php
/* assuming a mysqldump using --skip-extended-insert */
$last = '';
$count = 0;
$maxinserts = 10000;
while($l = fgets(STDIN)){
  if ( preg_match('/^(INSERT INTO .* VALUES) (.*);/',$l,$s) )
  {
    if ( $last != $s[1] || $count > $maxinserts )
    {
      if ( $count > $maxinserts ) // Limit the inserts
        echo ";\n";
      echo "$s[1] ";
      $comma = ''; 
      $last = $s[1];
      $count = 0;
    }
    echo "$comma$s[2]";
    $comma = ",\n";
  } elseif ( $last != '' ) {
    $last = '';
    echo ";\n";
  }
  $count++;
} 
0
Kjeld Flarup