it-swarm.com.ru

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

Об этом спрашивали несколько раз, но я не могу найти решение своей проблемы. В основном, при использовании mysqldump, который является встроенным инструментом для инструмента администрирования MySQL Workbench, когда я выгружаю базу данных, используя расширенные вставки, я получаю огромные длинные строки данных. Я понимаю, почему он это делает, поскольку он ускоряет вставки, вставляя данные в виде одной команды (особенно в InnoDB), но форматирование делает ДЕЙСТВИТЕЛЬНО затруднительным просмотр данных в файле дампа или сравнение двух файлов с помощью инструмента сравнения. если вы храните их в системе управления версиями и т. д. В моем случае я храню их в системе управления версиями, поскольку мы используем файлы дампа для отслеживания нашей базы данных тестов интеграции.

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

Моя основная проблема заключается в том, что в OLD-инструменте, который мы использовали (MySQL Administrator), когда я выгружаю файл, он делает в основном то же самое, но ФОРМАТИРУЕТ, что оператор 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 больше не доступна?

40
Kendall Bennett

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

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

Поэтому в идеале для эффективного восстановления базы данных в файле 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

В результате получается формат команды INSERT для файла sql:

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

Некоторые заметки:

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

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

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

31
Eric Tan

Как говорили другие, использование 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» для замены in-line.

Вот что делает этот код:

  1. --skip-extended-insert создаст один INSERT INTO для каждой вашей строки.
  2. Теперь мы используем sed для очистки данных. Обратите внимание, что обычный поиск/замена на sed применяется для одной строки, поэтому мы не можем обнаружить символ "\ n", так как sed работает по одной строке за раз. Вот почему мы ставим «: a; N; $! Ba;» который в основном говорит sed искать много строк и буферизовать следующую строку.

Надеюсь это поможет

10
Ace.Di

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

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

Это производит два файла:

  • 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 обычно в 20 раз быстрее, чем использование операторов INSERT.

Если вам нужно восстановить данные в другую таблицу (например, для проверки или тестирования), вы можете создать «зеркальную» таблицу:

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 и т.д.)

7
Cristian Porta

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

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

5
Mike Lischke

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

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

1
seanf

Мне нравилось решение Ace.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 также генерирует новый INSERT для каждых 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++;
} 
0
Kjeld Flarup