Как разделить вывод mysqldump на файлы меньшего размера?

Мне нужно переместить целые таблицы из одной базы данных MySQL в другую. У меня нет полного доступа ко второму, только доступ к phpMyAdmin. Я могу загружать только (сжатые) файлы sql размером менее 2 МБ. Но сжатый вывод mysqldump таблиц первой базы данных превышает 10 МБ.

Есть ли способ разделить вывод mysqldump на файлы меньшего размера? Я не могу использовать split (1), так как не могу вернуть файлы на удаленный сервер (1).

Или есть другое решение, которое я пропустил?

Редактировать

Опция --extended-insert = FALSE для mysqldump, предложенная первым постером, дает файл .sql, который затем может быть разделен на импортируемые файлы, при условии, что split (1) вызывается с подходящей опцией --lines. Методом проб и ошибок я обнаружил, что bzip2 сжимает файлы .sql в 20 раз, поэтому мне нужно было выяснить, сколько строк кода sql соответствует примерно 40 МБ.

посмотрите на этот Q, если вы ищете, как разбить большой дамп postgresql на файлы меньшего размера

rubo77 18.03.2017 18:03
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
46
1
69 351
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

Ответ принят как подходящий

Сначала сделайте дамп схемы (она точно умещается в 2 Мб, не так ли?)

mysqldump -d --all-databases 

и восстановить его.

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

mysqldump --all-databases --extended-insert=FALSE --no-create-info=TRUE

Я искал способ включить оператор INSERT для каждой вставленной строки, а не один массивный оператор с множеством кортежей или каждой строкой с использованием VALUES. Флаг --extended-insert=FALSE был тем, что мне было нужно. Благодарность!

dmkc 09.07.2012 23:52

Создать таблицу: mysqldump mydatabase mytable -d > mytable-create.sql Данные: mysqldump mydatabase mytable --extended-insert=FALSE --no-create-info=TRUE > mytable-data.sql Затем разделить ее на серию файлов любой длины: split mytable-data.sql -l10000 Теперь вы можете импортировать сначала созданный SQL. Затем каждая из таблиц длиной по 10 000 штук. По умолчанию файлы будут называться xaa, xab, xac ...). Важны они mysql mydatabase < xaa и т. д.

liamvictor 03.01.2018 16:12

Установка --extended-insert=FALSE сильно сократила для меня время импорта больших таблиц данных. Но я не понимаю, как это помогает. Даже если установлено значение TRUE, все операторы INSERT находятся в одной строке, поэтому вы можете безопасно разделить файл дампа на n строк, и единственное, что вы потеряете, - это блокировка при переключении на импорт дополнительных данных в ту же таблицу из следующей. файл (который вы можете восстановить, просто установив его cat).

Nikola Novak 25.11.2020 08:46

Попробуйте csplit (1), чтобы разделить вывод на отдельные таблицы на основе регулярных выражений (я бы подумал, что соответствует границе таблицы).

Вы можете сбрасывать отдельные таблицы с помощью mysqldump, запустив mysqldump database table1 table2 ... tableN

Если ни одна из таблиц не слишком велика, этого будет достаточно. В противном случае вам придется начать разбиение данных на большие таблицы.

Вы говорите, что у вас нет доступа ко второму серверу. Но если у вас есть доступ к первому серверу, где находятся таблицы, вы можете разделить дамп по таблицам:

for T in `mysql -N -B -e 'show tables from dbname'`; \
   do echo $T; \
   mysqldump [connecting_options] dbname $T \
   | gzip -c > dbname_$T.dump.gz ; \
   done

Это создаст файл gzip для каждой таблицы.

Другой способ разделить вывод mysqldump на отдельные файлы - использовать параметр --tab.

mysqldump [connecting options] --tab=directory_name dbname 

где имя_каталога - имя пустого каталога. Эта команда создает файл .sql для каждой таблицы, содержащий оператор CREATE TABLE, и файл .txt, содержащий данные, которые необходимо восстановить с помощью LOAD DATA INFILE. Однако я не уверен, может ли phpMyAdmin обрабатывать эти файлы с вашим конкретным ограничением.

Хотя это может не напрямую соответствовать потребностям OP, это отличный способ поместить отдельные таблицы в их собственные файлы ... для grep и т. д.

Joel Mellon 04.08.2012 00:13

Если во время выполнения этого сценария выполняется запись в какие-либо таблицы, резервное копирование будет в несогласованном состоянии.

None 30.10.2019 17:08

Вам не нужен ssh-доступ ни к одному из ваших серверов. Подойдет только клиент mysql [dump]. С помощью mysql [dump] вы можете выгрузить свою базу данных и снова импортировать ее.

На своем ПК вы можете сделать что-то вроде:

$ mysqldump -u originaluser -poriginalpassword -h originalhost originaldatabase | mysql -u newuser -pnewpassword -h newhost новая база данных

и вы сделали. :-)

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

Посмотрите SQLDumpSplitter 2, я просто успешно разбил дамп размером 40 МБ. Вы можете получить его по ссылке ниже:

sqldumpsplitter.com

Надеюсь на эту помощь.

SQLDumpSplitter2 может обрабатывать файлы размером только до 2 ГБ (2 147 483 648 байт - я думаю, он использует 32-битное целое число со знаком для размера файла). Было бы здорово изменить это или скомпилировать исходный исходный код для 64-битной версии, но я боюсь, что исходный код, вероятно, будет утерян. В остальном это отличный инструмент. Но многие проблемы с разделением файлов SQL начинаются где-то около 2 ГБ.

David Ferenczy Rogožan 01.07.2013 18:54

Привет, я просто хотел сообщить вам, что теперь доступна переписанная версия этой программы: philiplb.de/sqldumpsplitter3

Philip 28.12.2018 04:53

Поздний ответ, но искал такое же решение и наткнулся на следующий код с веб-сайта ниже:

for I in $(mysql -e 'show databases' -s --skip-column-names); do mysqldump $I | gzip > "$I.sql.gz"; done

http://www.commandlinefu.com/commands/view/2916/backup-all-mysql-databases-to-individual-files

Я бы порекомендовал утилиту bigdump, вы можете скачать ее здесь. http://www.ozerov.de/bigdump.php это замедляет выполнение дампа настолько близко, насколько это возможно к вашему пределу, выполняя целые строки за раз.

Этот сценарий bash разбивает файл дампа одной базы данных на отдельные файлы для каждой таблицы и имена с csplit и присваивает им соответствующие имена:

#!/bin/bash

####
# Split MySQL dump SQL file into one file per table
# based on https://gist.github.com/jasny/1608062
####

#adjust this to your case:
START = "/-- Table structure for table/"
# or 
#START = "/DROP TABLE IF EXISTS/"


if [ $# -lt 1 ] || [[ $1 == "--help" ]] || [[ $1 == "-h" ]] ; then
        echo "USAGE: extract all tables:"
        echo " $0 DUMP_FILE"
        echo "extract one table:"
        echo " $0 DUMP_FILE [TABLE]"
        exit
fi

if [ $# -ge 2 ] ; then
        #extract one table $2
        csplit -s -ftable $1 "/-- Table structure for table/" "%-- Table structure for table \`$2\`%" "/-- Table structure for table/" "%40103 SET TIME_ZONE=@OLD_TIME_ZONE%1"
else
        #extract all tables
        csplit -s -ftable $1 "$START" {*}
fi
 
[ $? -eq 0 ] || exit
 
mv table00 head
 
FILE=`ls -1 table* | tail -n 1`
if [ $# -ge 2 ] ; then
        # cut off all other tables
        mv $FILE foot
else
        # cut off the end of each file
        csplit -b '%d' -s -f$FILE $FILE "/40103 SET TIME_ZONE=@OLD_TIME_ZONE/" {*}
        mv ${FILE}1 foot
fi
 
for FILE in `ls -1 table*`; do
        NAME=`head -n1 $FILE | cut -d$'\x60' -f2`
        cat head $FILE foot > "$NAME.sql"
done
 
rm head foot table*

на основе https://gist.github.com/jasny/1608062
и https://stackoverflow.com/a/16840625/1069083

Следует отметить, что csplit на Mac не работает с этим скриптом, потому что он не поддерживает синтаксис {*}. Нужно запустить его в Linux.

rlorenzo 07.02.2014 04:20

То же самое и во FreeBSD. Но вы можете установить туда порт или пакет sysutils / coreutils, чтобы получить утилиты GNU и вместо этого использовать gcsplit.

Dereckson 15.11.2014 20:31

Ой, я не могу, чем тебя хватит для этого сценария. У меня был mysqlDump емкостью 3 ТБ, который дважды терпел неудачу, и теперь я могу импортировать его таблицу за таблицей и продолжить с того места, где я оставил, если он не удастся. Тебе прислали много любви.

Bathan 19.03.2018 17:16

Да лучше всего. mysqldump не работает с параметром --tab, если база данных находится на другом сервере, кроме localhost. Таким образом, вы можете выгрузить всю базу данных, перенаправить вывод в один файл, а затем разделить таблицы с помощью этого сценария! Но я ищу способ сделать как параметр --tab: разделить структуру как файл sql и данные как данные, разделенные табуляцией txt. Какой-нибудь волшебный сценарий для этого, или я бы создал другой сценарий разделения и преобразования?

kokbira 09.04.2019 16:13

Этот сценарий должен это делать:

#!/bin/sh

#edit these
USER = ""
PASSWORD = ""
MYSQLDIR = "/path/to/backupdir"

MYSQLDUMP = "/usr/bin/mysqldump"
MYSQL = "/usr/bin/mysql"

echo - Dumping tables for each DB
databases=`$MYSQL --user=$USER --password=$PASSWORD -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema)"`
for db in $databases; do
    echo - Creating "$db" DB
    mkdir $MYSQLDIR/$db
    chmod -R 777 $MYSQLDIR/$db
    for tb in `$MYSQL  --user=$USER --password=$PASSWORD -N -B -e "use $db ;show tables"`
        do 
            echo -- Creating table $tb
            $MYSQLDUMP --opt  --delayed-insert --insert-ignore --user=$USER --password=$PASSWORD $db $tb | bzip2 -c > $MYSQLDIR/$db/$tb.sql.bz2
    done
    echo
done

Я создал MySQLDumpSplitter.java, который, в отличие от сценариев bash, работает в Windows. Это доступно здесь https://github.com/Verace/MySQLDumpSplitter.

Недавно я создал sqlsplit.com. Попробуйте сами.

ваше приложение отлично работает, но что вы делаете с загруженными файлами?

Daniël Tulp 03.09.2018 16:28

@ DaniëlTulp Ничего. Загруженные файлы удаляются сразу после разделения и отправки пользователю. github.com/sqlsplit/sqlsplit/blob/master/public/index.php#L3‌ 8

vbarbarosh 03.09.2018 20:45

возможно, добавьте заявление о конфиденциальности по этому поводу (также, чтобы соответствовать GDPR, спасибо за приложение, использовал его для восстановления рабочего веб-сайта

Daniël Tulp 03.09.2018 22:27

@ DaniëlTulp Только что добавлен диалог конфиденциальности.

vbarbarosh 04.09.2018 21:11

Вы можете разбить существующий файл по AWK. Это очень быстро и просто

Разобьем дамп таблицы на «таблицы»:

cat dump.sql | awk 'BEGIN {output = "comments"; }
$data ~ /^CREATE TABLE/ {close(output); output = substr(,2,length()-2); }
{ print $data >> output }';

Или вы можете разделить дамп по базе данных

cat backup.sql | awk 'BEGIN {output = "comments";} $data ~ /Current Database/ {close(output);output=;} {print $data>>output}';

Есть отличный скрипт mysqldumpsplitter, который имеет множество опций, когда дело доходит до извлечения из mysqldump.

Я бы скопировал рецепт сюда, чтобы выбрать свой случай из:

1) Extract single database from mysqldump:

sh mysqldumpsplitter.sh --source filename --extract DB --match_str database-name

Above command will create sql for specified database from specified "filename" sql file and store it in compressed format to database-name.sql.gz.

2) Extract single table from mysqldump:

sh mysqldumpsplitter.sh --source filename --extract TABLE --match_str table-name

Above command will create sql for specified table from specified "filename" mysqldump file and store it in compressed format to database-name.sql.gz.

3) Extract tables matching regular expression from mysqldump:

sh mysqldumpsplitter.sh --source filename --extract REGEXP --match_str regular-expression

Above command will create sqls for tables matching specified regular expression from specified "filename" mysqldump file and store it in compressed format to individual table-name.sql.gz.

4) Extract all databases from mysqldump:

sh mysqldumpsplitter.sh --source filename --extract ALLDBS

Above command will extract all databases from specified "filename" mysqldump file and store it in compressed format to individual database-name.sql.gz.

5) Extract all table from mysqldump:

sh mysqldumpsplitter.sh --source filename --extract ALLTABLES

Above command will extract all tables from specified "filename" mysqldump file and store it in compressed format to individual table-name.sql.gz.

6) Extract list of tables from mysqldump:

sh mysqldumpsplitter.sh --source filename --extract REGEXP --match_str '(table1|table2|table3)'

Above command will extract tables from the specified "filename" mysqldump file and store them in compressed format to individual table-name.sql.gz.

7) Extract a database from compressed mysqldump:

sh mysqldumpsplitter.sh --source filename.sql.gz --extract DB --match_str 'dbname' --decompression gzip

Above command will decompress filename.sql.gz using gzip, extract database named "dbname" from "filename.sql.gz" & store it as out/dbname.sql.gz

8) Extract a database from compressed mysqldump in an uncompressed format:

sh mysqldumpsplitter.sh --source filename.sql.gz --extract DB --match_str 'dbname' --decompression gzip --compression none

Above command will decompress filename.sql.gz using gzip and extract database named "dbname" from "filename.sql.gz" & store it as plain sql out/dbname.sql

9) Extract alltables from mysqldump in different folder:

sh mysqldumpsplitter.sh --source filename --extract ALLTABLES --output_dir /path/to/extracts/

Above command will extract all tables from specified "filename" mysqldump file and extracts tables in compressed format to individual files, table-name.sql.gz stored under /path/to/extracts/. The script will create the folder /path/to/extracts/ if not exists.

10) Extract one or more tables from one database in a full-dump:

Consider you have a full dump with multiple databases and you want to extract few tables from one database.

Extract single database: sh mysqldumpsplitter.sh --source filename --extract DB --match_str DBNAME --compression none

Extract all tables sh mysqldumpsplitter.sh --source out/DBNAME.sql --extract REGEXP --match_str "(tbl1|tbl2)" though we can use another option to do this in single command as follows:

sh mysqldumpsplitter.sh --source filename --extract DBTABLE --match_str "DBNAME.(tbl1|tbl2)" --compression none

Above command will extract both tbl1 and tbl2 from DBNAME database in sql format under folder "out" in current directory.

You can extract single table as follows:

sh mysqldumpsplitter.sh --source filename --extract DBTABLE --match_str "DBNAME.(tbl1)" --compression none

11) Extract all tables from specific database:

mysqldumpsplitter.sh --source filename --extract DBTABLE --match_str "DBNAME.*" --compression none

Above command will extract all tables from DBNAME database in sql format and store it under "out" directory.

12) List content of the mysqldump file

mysqldumpsplitter.sh --source filename --desc

Above command will list databases and tables from the dump file.

Позже вы можете выбрать загрузку файлов: zcat filename.sql.gz | mysql -uUSER -p -h ИМЯ ХОСТА

  • Кроме того, как только вы извлечете одну таблицу, которая, по вашему мнению, еще больше, вы можете использовать команду разделения linux с количеством строк для дальнейшего разделения дампа. split -l 10000 filename.sql

  • Тем не менее, если это вам нужно (приходите чаще), вы можете подумать об использовании mydumper, который фактически создает отдельные дампы, которые вам не нужно разделять!

Я должен дополнить вас в вашем сценарии bash. У меня была огромная резервная копия базы данных, и мне потребовалось около 60 часов, чтобы разделить базу данных. Я волновался, что ваш сценарий может сломаться, но он работал как шарм. Спасибо и продолжайте в том же духе.

Sadegh Ameri 30.10.2019 13:34

Это было так полезно! Спасибо за публикацию

Greg Alexander 10.03.2021 00:11

Пояснение к ответу @ Vérace:

Мне особенно нравится интерактивный метод; вы можете разделить большой файл в Eclipse. Я успешно пробовал файл размером 105 ГБ в Windows:

Просто добавьте в свой проект библиотеку MySQLDumpSplitter: http://dl.bintray.com/verace/MySQLDumpSplitter/jar/

Краткое примечание о том, как импортировать:

- In Eclipse, Right click on your project --> Import
- Select "File System" and then "Next"
- Browse the path of the jar file and press "Ok"
- Select (thick) the "MySQLDumpSplitter.jar" file and then "Finish"
- It will be added to your project and shown in the project folder in Package Explorer in Eclipse
- Double click on the jar file in Eclipse (in Package Explorer)
- The "MySQL Dump file splitter" window opens which you can specify the address of your dump file and proceed with split.

Попробуйте это: https://github.com/shenli/mysqldump-hugetable Он сбрасывает данные во множество небольших файлов. Каждый файл содержит меньше или равно MAX_RECORDS записей. Вы можете установить этот параметр в env.sh.

Я написал новую версию SQLDumpSplitter, на этот раз с правильным парсером, позволяющим разделять такие приятные вещи, как INSERT со многими значениями, по файлам, и теперь это мультиплатформенный: https://philiplb.de/sqldumpsplitter3/

Я написал сценарий Python для разделения одного большого файла дампа sql на отдельные файлы, по одному для каждого оператора CREATE TABLE. Он записывает файлы в новую указанную вами папку. Если выходная папка не указана, создается новая папка с тем же именем, что и файл дампа, в том же каталоге. Он работает построчно, без предварительной записи файла в память, поэтому отлично подходит для больших файлов.

https://github.com/kloddant/split_sql_dump_file

import sys, re, os

if sys.version_info[0] < 3:
    raise Exception("""Must be using Python 3.  Try running "C:\Program Files (x86)\Python37-32\python.exe" split_sql_dump_file.py""")

sqldump_path = input("Enter the path to the sql dump file: ")

if not os.path.exists(sqldump_path):
    raise Exception("Invalid sql dump path.  {sqldump_path} does not exist.".format(sqldump_path=sqldump_path))

output_folder_path = input("Enter the path to the output folder: ") or sqldump_path.rstrip('.sql')

if not os.path.exists(output_folder_path):
    os.makedirs(output_folder_path)

table_name = None
output_file_path = None
smallfile = None

with open(sqldump_path, 'rb') as bigfile:
    for line_number, line in enumerate(bigfile):
        line_string = line.decode("utf-8")
        if 'CREATE TABLE' in line_string.upper():
            match = re.match(r"^CREATE TABLE (?:IF NOT EXISTS )?`(?P<table>\w+)` \($", line_string)
            if match:
                table_name = match.group('table')
                print(table_name)
                output_file_path = "{output_folder_path}/{table_name}.sql".format(output_folder_path=output_folder_path.rstrip('/'), table_name=table_name)
                if smallfile:
                    smallfile.close()
                smallfile = open(output_file_path, 'wb')
        if not table_name:
            continue
        smallfile.write(line)
    smallfile.close()

Другие вопросы по теме