Используя mysqldump в формате одна вставка на линию?

Это было предложено несколько раз, но я не могу найти решение моей проблемы. В основном при использовании mysqldump, который является встроенным инструментом для инструмента администрирования MySQL Workbench, когда я сбрасываю базу данных с помощью расширенных вставок, я получаю массивные длинные строки данных. Я понимаю, почему он это делает, поскольку он ускоряет вставки, вставляя данные как одну команду( особенно на InnoDB), но форматирование действительно затрудняет просмотр данных в файле дампа или сравнение двух файлов с помощью дифф, если вы храните их в систему управления версиями и т. д. В моем случае я храню их в version control, поскольку мы используем файлы дампа для отслеживания нашей тестовой базы данных интеграции.

теперь я знаю, что могу отключить расширенные вставки, поэтому я получу одну вставку в строку, которая работает, но каждый раз, когда вы делаете восстановление с файлом дампа, он будет медленнее.

моя основная проблема заключается в том, что в старом инструменте, который мы использовали (администратор MySQL), когда я сбрасываю файл, он делает в основном то же самое, но он форматирует оператор INSERT, чтобы поместить одну вставку в строку, все еще делая массовые вставки. Поэтому вместо этого:

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 больше не доступна?

7 ответов


с форматом mysqldump по умолчанию каждая сброшенная запись будет генерировать отдельную команду INSERT в файле дампа (т. е. файл sql), каждый в своей собственной строке. Это идеально подходит для управления версиями (например, svn, git и т. д.) поскольку это делает разрешение diff и delta намного тоньше и в конечном итоге приводит к более эффективному процессу управления версиями. Однако для таблиц значительного размера выполнение всех этих запросов INSERT потенциально может привести к запретительному восстановлению из файла sql медленный.

использование опции --extended-insert устраняет проблему множественной вставки путем упаковки всех записей в одну команду INSERT в одной строке в сброшенном файле sql. Однако процесс управления версиями становится очень неэффективным. Все содержимое таблицы представлено в одной строке в файле sql, и если один символ изменяется в любом месте этой таблицы, элемент управления версиями будет помечать всю строку (т. е. всю таблицу) как дельта между версиями. И, для больших таблицы, это отрицает многие преимущества использования формальной системы управления версиями.

поэтому в идеале для эффективного восстановления базы данных в файле sql мы хотим, чтобы каждая таблица была представлена одной вставкой. Для эффективного процесса управления версиями в файле 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 INTO `mytable` VALUES
(r1c1value, r1c2value, r1c3value),
(r2c1value, r2c2value, r2c3value),
(r3c1value, r3c2value, r3c3value);

некоторые замечания:

  • пароль в командной строке ... Я знаю, не безопасное, другое обсуждение.
  • --opt: среди прочего, включает опцию --extended-insert (т. е. одну вставку на таблицу).
  • --skip-dump-date: mysqldump обычно помещает отметку даты/времени в файл sql при создании. Это может стать раздражающим в системе управления версиями, когда единственная дельта между версиями-это отметка даты/времени. ОС и источник система управления отметит дату / время файла и версии. Его действительно не нужно в файле sql.
  • команды git не являются центральными для фундаментального вопроса (форматирование файла sql), но показывает, как я возвращаю свой файл sql в систему управления версиями, что-то подобное можно сделать с svn. При объединении этого формата файла sql с выбранным исходным кодом вы обнаружите, что при обновлении пользователями своих рабочих копий им нужно только переместить дельты (т. е. измененные записи) через интернет, и они могут воспользоваться преимуществами утилит diff, чтобы легко увидеть, какие записи в базе данных изменились.
  • если вы сбрасываете базу данных, которая находится на удаленном сервере, если это возможно, запустите этот скрипт на этом сервере, чтобы избежать перемещения всего содержимого базы данных по сети с каждым дампом.
  • если возможно, установите рабочий репозиторий управления версиями для ваших файлов sql на том же сервере, с которого вы запускаете этот скрипт; проверьте их оттуда в хранилище. Это также поможет предотвратить необходимость перемещения всей базы данных по сети с каждым дампом.

попробуйте использовать следующую опцию: --skip-extended-insert

Это сработало для меня.


Как говорили другие, используя sed для замены "), ("небезопасно, поскольку это может отображаться как содержимое в базе данных. Однако есть способ сделать это: если имя базы данных-my_database, выполните следующие действия:

$ 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. --пропустить расширенная вставка зделал вставить в каждый ряд у вас.
  2. теперь мы используем sed для очистки данных. Заметить что регулярный поиск / замена на sed применяется для одной строки, поэтому мы не можем обнаружить символ "\n", поскольку sed работает по одной строке за раз. Вот почему мы ставим ": a; N;$!ba; " который в основном говорит sed искать многострочный и буферизировать следующую строку.

надеюсь, что это помогает


как насчет хранения дампа в CSV-файл с mysqldump, используя --tab такой вариант?

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

это создает два файла:

  • table_a.sql который содержит только инструкцию table create; и
  • table_a.txt который содержит данные, разделенные вкладками.

восстановление

вы можете восстановить таблицы с помощью LOAD DATA:

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

данные по нагрузки обычно 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 прост для различий или для просмотра внутри, или для не-SQL технических пользователей, которые могут использовать общие инструменты, такие как Excel, Access или командной строки (diff, comm, etc...)


боюсь, это невозможно. В старом администраторе MySQL я написал код для сброса объектов db, который был полностью независим от инструмента mysqldump и, следовательно, предложил ряд дополнительных опций (например, это форматирование или обратная связь прогресса). В MySQL Workbench было решено использовать инструмент mysqldump, который, помимо того, что является шагом назад в некоторых отношениях и создает проблемы с версией, имеет преимущество оставаться всегда в курсе сервер.

Итак, короткий ответ: форматирование в настоящее время невозможно с mysqldump.


Я нашел этот инструмент очень полезным для работы с расширенными вставками:http://blog.lavoie.sl/2014/06/split-mysqldump-extended-inserts.html

он анализирует вывод mysqldump и вставляет linebreaks после каждой записи, но все еще использует более быстрые расширенные вставки. В отличие от сценария sed, не должно быть никакого риска разрыва строк в неправильном месте, если регулярное выражение совпадает внутри строки.


мне понравился Туз.Решение Di с sed, пока я не получил эту ошибку: 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 строк, чтобы избежать проблем с памятью.

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++;
}