dump all mysql tables into separate files automatically?

Viewed 88216

I'd like to get dumps of each mysql table into separate files. The manual indicates that the syntax for this is

mysqldump [options] db_name [tbl_name ...]

Which indicates that you know the table names before hand. I could set up the script that knows each table name now, but say I add a new table down the road and forget to update the dump script. Then I'm missing dumps for one or more table.

Is there a way to automagically dump each existing table into a separate file? Or am I going to have to do some script-fu; query the database, get all the table names, and dump them by name.

If I go the script-fu route, what scripting langauges can access a mysql database?

11 Answers

If You want to dump all tables from all databases just combine Elias Torres Arroyo's and Trutane's answer: And if You don't want to give Your password on terminal, just store Your password in an extra config file (chmod 0600)- see Mysqldump launched by cron and password security

#!/bin/bash

# this file
# a) gets all databases from mysql
# b) gets all tables from all databases in a)
# c) creates subfolders for every database in a)
# d) dumps every table from b) in a single file

    # this is a mixture of scripts from Trutane (http://stackoverflow.com/q/3669121/138325) 
    # and Elias Torres Arroyo (https://stackoverflow.com/a/14711298/8398149)

# usage: 
# sk-db.bash parameters
# where pararmeters are:

# d "dbs to leave"
# t " tables to leave"
# u "user who connects to database"
# h "db host"
# f "/backup/folder"



user='root'
host='localhost'
backup_folder=''
leave_dbs=(information_schema mysql)
leave_tables=()
while getopts ":d:t:u:h:f:" opt; do
  case $opt in
    d) leave_dbs=( $OPTARG )
    ;;
    t) leave_tables=( $OPTARG )
    ;;
    u) user=$OPTARG
    ;;
    h) host=$OPTARG
    ;;
    f) backup_folder=$OPTARG
    ;;

    \?) echo "Invalid option -$OPTARG" >&2
    ;;
  esac
done
echo '****************************************'
echo "Database Backup with these options"
echo "Host $host"
echo "User $user"
echo "Backup in $backup_folder"
echo '----------------------------------------'
echo "Databases to emit:"
printf "%s\n" "${leave_dbs[@]}"
echo '----------------------------------------'
echo "Tables to emit:"
printf "%s\n" "${leave_tables[@]}"
echo '----------------------------------------'


BACKUP_DIR=$backup_folder/$(date +%Y-%m-%dT%H_%M_%S);
CONFIG_FILE=/root/db-config.cnf

function contains() {
    local n=$#
    local value=${!n}
    for ((i=1;i < $#;i++)) {
        if [ "${!i}" == "${value}" ]; then
            echo "y"
            return 0
        fi
    }
    echo "n"
    return 1
}


test -d "$BACKUP_DIR" || mkdir -p "$BACKUP_DIR"
# Get the database list, exclude information_schema
database_count=0
tbl_count=0

for db in $(mysql --defaults-extra-file=$CONFIG_FILE -B -s -u $user -e 'show databases' )
do
    if [ $(contains "${leave_dbs[@]}" "$db") == "y" ]; then
        echo "leave database $db as requested"
    else

       # dump each database in a separate file
       (( database_count++ ))
       DIR=$BACKUP_DIR/$db
       [ -n "$DIR" ] || DIR=.

       test -d $DIR || mkdir -p $DIR

       echo
       echo "Dumping tables into separate SQL command files for database '$db' into dir=$DIR"

       for t in $(mysql --defaults-extra-file=$CONFIG_FILE -NBA -h $host -u $user -D $db -e 'show tables')
       do
           if [ $(contains "${leave_tables[@]}" "$db.$t") == "y" ]; then
               echo "leave table $db.$t as requested"
           else
               echo "DUMPING TABLE: $db.$t"
  #            mysqldump --defaults-extra-file=$CONFIG_FILE -h $host -u $user $db $t  > $DIR/$db.$t.sql
               tbl_count=$(( tbl_count + 1 ))
           fi
       done

       echo "Database $db is finished"
       echo '----------------------------------------'

    fi
done
echo '----------------------------------------'
echo "Backup completed"
echo '**********************************************'

And also, this helped:

Check if bash array contains value

arrays in bash

named arguments in script

I have had recently the need to backup a big database (more than 250GB uncompressed dump file) and I found the answers to this question really helpful.

I started using @Trutane approach and it worked like a charm. But I was concerned about dumping tables in different mysql sessions because that could, in some moment, drive to a non-consistent backup.

After some research and testing, I have developed a different solution based on gawk. The basic idea is creating a dump of the whole database using mysqldump with --single-transaction=true and then process the output with gawk to produce a different file for every table.

So I can call:

mysqldump --single-transaction=true -u DBUSERNAME -p DBNAME | \
  gawk -v 'database=DBNAME' -f 'backup.awk' -

And it produces, in current folder, a bunch of $database.$table.sql files with the schema of every table and $database.$table.sql.gz files with the content of every table. Thanks to the param --single-transaction=true, all the dump happens in a single transaction and data consistency is ensured.

The content of backup.awk is:

# Split mysqldump output in different files, two per table:
# * First file is named $database.$table.sql and it contains the table schema
# * Second file is named $database.$table.sql.gz and it contains the table data 

# The 'database' variable is expected to be provided in command-line
BEGIN {
    insert=0
    filename=sprintf("%s.header.sql", database);
}

# A line starting with "INSERT INTO" activates inserting mode
/INSERT INTO/       { insert=1 }

# A line containing "-- Table structure for table `name-of-table`" finishes inserting mode
# It is also used to detect table name and change file names accordingly
match($0, /-- Table structure for table `(.*)`/, m) {
    insert=0;
    table=m[1];
    filename=sprintf("%s.%s.sql", database, table);
    print sprintf("Dumping table %s\n", table);
}

# If in inserting mode, line is piped to a gzipped file,
#and else it redirected to an uncompressed schema file
{
    if (insert == 1) {
       output = sprintf("gzip > %s.gz", filename);
       print | output
    } else {
       print > filename;
    }
}

For Windows Servers, you can use a batch file like so:

set year=%DATE:~10,4%
set day=%DATE:~7,2%
set mnt=%DATE:~4,2%
set hr=%TIME:~0,2%
set min=%TIME:~3,2%

IF %day% LSS 10 SET day=0%day:~1,1%
IF %mnt% LSS 10 SET mnt=0%mnt:~1,1%
IF %hr% LSS 10 SET hr=0%hr:~1,1%
IF %min% LSS 10 SET min=0%min:~1,1%

set backuptime=%year%-%mnt%-%day%-%hr%-%min%
set backupfldr=C:\inetpub\wwwroot\backupfiles\
set datafldr="C:\Program Files\MySQL\MySQL Server 5.5\data"
set zipper="C:\inetpub\wwwroot\backupfiles\zip\7za.exe"
set retaindays=21

:: Switch to the data directory to enumerate the folders
pushd %datafldr%

:: Get all table names and save them in a temp file
mysql --skip-column-names --user=root --password=mypassword mydatabasename -e "show tables" > tables.txt

:: Loop through all tables in temp file so that we can save one backup file per table
for /f "skip=3 delims=|" %%i in (tables.txt) do (
  set tablename = %%i
  mysqldump --user=root --password=mypassword mydatabasename %%i > "%backupfldr%mydatabasename.%backuptime%.%%i.sql"
)
del tables.txt

:: Zip all files ending in .sql in the folder
%zipper% a -tzip "%backupfldr%backup.mydatabasename.%backuptime%.zip" "%backupfldr%*.sql"

echo "Deleting all the files ending in .sql only"
del "%backupfldr%*.sql"

echo "Deleting zip files older than 21 days now"
Forfiles /p %backupfldr% /m *.zip /d -%retaindays% /c "cmd /c del /q @path"

Then schedule it using Windows Task Scheduler.

Also, if you want to exclude certain tables in your backup, note that you can use a where clause on the "show tables" statement, but the column name depends on your database name.

So for example, if your database name is "blah" then your column name in the "show tables" result set will be "tables_in_blah". Which means you could add a where clause something similar to this:

show tables where tables_in_blah <> 'badtable'

or

show tables where tables_in_blah like '%goodtable%'
Related