J'aimerais écrire un script qui copie ma base de données actuelle sitedb1
dans sitedb2
sur la même instance de base de données mysql. Je sais que je peux transférer le fichier sitedb1 dans un script SQL:
mysqldump -u root -p sitedb1 >~/db_name.sql
puis importez-le dans sitedb2
. Y at-il un moyen plus facile, sans vider la première base de données dans un fichier SQL?
Comme le dit le manuel dans Copier des bases de données vous pouvez diriger le dump directement dans le client mysql:
mysqldump db_name | mysql new_db_name
Si vous utilisez MyISAM, vous pouvez copier les fichiers, mais je ne le recommanderais pas. C'est un peu louche.
Intégré à partir de diverses bonnes autres réponses
Les commandes mysqldump
et mysql
acceptent les options permettant de définir les détails de connexion (et bien plus encore), telles que:
mysqldump -u <user name> --password=<pwd> <original db> | mysql -u <user name> -p <new db>
De plus, si la nouvelle base de données n’existe pas encore, vous devez la créer au préalable (par exemple avec echo "create database new_db_name" | mysql -u <dbuser> -p
).
Les utilitaires MySQL contiennent l’outil Nice mysqldbcopy
qui copie par défaut une base de données, y compris tous les objets associés ("tables, vues, déclencheurs, événements, procédures, fonctions et attributions au niveau de la base de données") identique ou à un autre serveur de base de données. Il y a beaucoup d'options disponibles pour personnaliser ce qui est réellement copié.
Donc, pour répondre à la question du PO:
mysqldbcopy \
--source=root:your_password@localhost \
--destination=root:your_password@localhost \
sitedb1:sitedb2
$ mysqladmin create DB_name -u DB_user --password=DB_pass && \
mysqldump -u DB_user --password=DB_pass DB_name | mysql -u DB_user --password=DB_pass -h DB_Host DB_name
Vous devez exécuter la commande à partir du terminal/invite de commande.
mysqldump -u <user name> -p <pwd> <original db> | mysql -u <user name> <pwd> <new db>
par exemple: mysqldump -u root test_db1 | mysql -u root test_db2
Ceci copie test_db1 dans test_db2 et accorde l’accès à 'root' @ 'localhost'
Vous pouvez utiliser (en pseudocode):
FOREACH tbl IN db_a:
CREATE TABLE db_b.tbl LIKE db_a.tbl;
INSERT INTO db_b.tbl SELECT * FROM db_a.tbl;
La raison pour laquelle je n'utilise pas la syntaxe CREATE TABLE ... SELECT ... est de conserver les index. Bien sûr, cela ne copie que les tables. Les vues et les procédures ne sont pas copiées, bien que cela puisse être fait de la même manière.
Voir CREATE TABLE .
Le meilleur moyen consiste à entrer ces commandes dans votre terminal et à définir des autorisations pour l'utilisateur root. Travaille pour moi..!
:~$> mysqldump -u root -p db1 > dump.sql
:~$> mysqladmin -u root -p create db2
:~$> mysql -u root -p db2 < dump.sql
Commencez par créer la base de données en double:
CREATE DATABASE duplicateddb;
Assurez-vous que les autorisations, etc. sont toutes en place et:
mysqldump -u admin -p originaldb | mysql -u backup -p password duplicateddb;
Vous pouvez faire quelque chose comme ce qui suit:
mysqldump -u[username] -p[password] database_name_for_clone
| mysql -u[username] -p[password] new_database_name
Cette instruction a été ajoutée dans MySQL 5.1.7 mais s'est avérée dangereuse et a été supprimée dans MySQL 5.1.23. L'objectif était de permettre à la mise à niveau des bases de données antérieures à la version 5.1 d'utiliser le codage implémenté dans la version 5.1 pour mapper les noms de bases de données sur les noms de répertoires de bases de données. Toutefois, l'utilisation de cette instruction peut entraîner une perte du contenu de la base de données, raison pour laquelle elle a été supprimée. N'utilisez pas RENAME DATABASE dans les versions antérieures où il est présent.
Pour effectuer la mise à niveau des noms de base de données avec le nouveau codage, utilisez ALTER DATABASE nom_bdd UPGRADE DATA DIRECTORY NAME à la place: http://dev.mysql.com/doc/refman/5.1/fr/alter-database.html
Il est préférable d'utiliser la commande mysqldbcopy
pour copier la base de données d'un serveur à un autre ou au même serveur.
mysqldbcopy --source=root:root@localhost --destination=root:root@localhost database-name:database-name-clone
Un moyen simple de le faire si vous avez installé phpmyadmin :
Allez dans votre base de données, sélectionnez l'onglet "opération", et vous pouvez voir le bloc "copier la base de données dans" Utilisez-le et vous pouvez copier la base de données.
Comme mentionné dans réponse de Greg , mysqldump db_name | mysql new_db_name
est le moyen gratuit, sûr et facile de transférer des données entre des bases de données. Cependant, c'est aussi très lent.
Si vous souhaitez sauvegarder des données, si vous ne pouvez pas vous permettre de perdre des données (dans cette base de données ou dans d'autres), ou utilisez des tables autres que innodb
, vous devez utiliser mysqldump
.
Si vous recherchez quelque chose à développer, que toutes vos bases de données soient sauvegardées ailleurs et que vous pouvez facilement purger et réinstaller mysql
(éventuellement manuellement) lorsque tout va mal, je pourrais peut-être trouver la solution.
Je ne pouvais pas trouver une bonne alternative, alors j'ai construit un script pour le faire moi-même. J'ai passé beaucoup de temps à obtenir que cela fonctionne la première fois et honnêtement, cela me terrifie un peu de le modifier maintenant. Les bases de données Innodb n'étaient pas destinées à être copiées et collées de la sorte. De petits changements entraînent un échec magnifique. Je n'ai pas eu de problème depuis la finalisation du code, mais cela ne veut pas dire que vous ne le ferez pas.
Systèmes testés sur (mais peuvent toujours échouer):
Sudo
et vérifie que vous disposez de suffisamment d'espace de stockage pour cloner la base de données.mysqldump
Sur une base de données de 3 Go, utiliser mysqldump
et mysql
prendrait 40 à 50 minutes sur ma machine. En utilisant cette méthode, le même processus ne prendrait que 8 minutes environ.
Nos modifications SQL sont enregistrées avec notre code et le processus de mise à niveau est automatisé à la fois en production et en développement, chaque ensemble de modifications effectuant une sauvegarde de la base de données à restaurer en cas d'erreur. Un problème que nous avons rencontré concernait le fait que nous travaillions sur un projet à long terme avec des modifications de la base de données et que nous devions changer de branche au milieu pour résoudre un ou plusieurs bugs.
Dans le passé, nous utilisions une base de données unique pour toutes les branches et nous devions la reconstruire chaque fois que nous passions à une branche non compatible avec les nouvelles modifications de la base de données. Et lorsque nous sommes revenus, nous devions relancer les mises à niveau.
Nous avons essayé mysqldump
de dupliquer la base de données pour différentes branches, mais le temps d'attente était trop long (40 à 50 minutes) et nous ne pouvions rien faire d'autre dans l'intervalle.
Cette solution a raccourci le temps de clonage de la base de données à 1/5 du temps (pensez au café et à la pause de la salle de bain au lieu d’un long repas).
La commutation entre des branches avec des modifications de base de données incompatibles prend plus de 50 minutes sur une seule base de données, mais aucune heure après la configuration initiale avec mysqldump
ou ce code. Ce code est environ 5 fois plus rapide que mysqldump
.
Voici quelques tâches courantes et leur durée approximative avec chaque méthode:
mysqldump
: 50 à 60 minutesmaster
pour une correction de bogue, effectuez une modification sur la branche de fonctionnalité et fusionnez:mysqldump
: 50 à 60 minutesmaster
pour une correction de bogue tout en apportant des modifications sur la branche de fonctionnalité entre-deux, puis fusionnez:mysqldump
: 50 à 60 minutesN'utilisez pas ceci à moins d'avoir lu et compris tout ce qui précède.
#!/bin/bash
set -e
# This script taken from: https://stackoverflow.com/a/57528198/526741
function now {
date "+%H:%M:%S";
}
# Leading space sets messages off from step progress.
echosuccess () {
printf "\e[0;32m %s: %s\e[0m\n" "$(now)" "$1"
sleep .1
}
echowarn () {
printf "\e[0;33m %s: %s\e[0m\n" "$(now)" "$1"
sleep .1
}
echoerror () {
printf "\e[0;31m %s: %s\e[0m\n" "$(now)" "$1"
sleep .1
}
echonotice () {
printf "\e[0;94m %s: %s\e[0m\n" "$(now)" "$1"
sleep .1
}
echoinstructions () {
printf "\e[0;104m %s: %s\e[0m\n" "$(now)" "$1"
sleep .1
}
echostep () {
printf "\e[0;90mStep %s of 13:\e[0m\n" "$1"
sleep .1
}
MYSQL_CNF_PATH='/etc/mysql/mysql.conf.d/recovery.cnf'
OLD_DB='YOUR_DATABASE_NAME'
USER='YOUR_MYSQL_USER'
# You can change NEW_DB to whatever you like
# Right now, it will append the current git branch name to the existing database name
BRANCH=`git rev-parse --abbrev-ref HEAD`
NEW_DB="${OLD_DB}__$BRANCH"
THIS_DIR=./site/upgrades
DB_CREATED=false
tmp_file () {
printf "$THIS_DIR/$NEW_DB.%s" "$1"
}
sql_on_new_db () {
mysql $NEW_DB --unbuffered --skip-column-names -u root -p$PASS 2>> $(tmp_file 'errors.log')
}
general_cleanup () {
echoinstructions 'Leave this running while things are cleaned up...'
if [ -f $(tmp_file 'errors.log') ]; then
echowarn 'Additional warnings and errors:'
cat $(tmp_file 'errors.log')
fi
for f in $THIS_DIR/$NEW_DB.*; do
echonotice 'Deleting temporary files created for transfer...'
rm -f $THIS_DIR/$NEW_DB.*
break
done
echonotice 'Done!'
echoinstructions "You can close this now :)"
}
error_cleanup () {
exitcode=$?
# Just in case script was exited while in a Prompt
echo
if [ "$exitcode" == "0" ]; then
echoerror "Script exited prematurely, but exit code was '0'."
fi
echoerror "The following command on line ${BASH_LINENO[0]} exited with code $exitcode:"
echo " $BASH_COMMAND"
if [ "$DB_CREATED" = true ]; then
echo
echonotice "Dropping database \`$NEW_DB\` if created..."
echo "DROP DATABASE \`$NEW_DB\`;" | sql_on_new_db || echoerror "Could not drop database \`$NEW_DB\` (see warnings)"
fi
general_cleanup
exit $exitcode
}
trap error_cleanup EXIT
mysql_path () {
printf "/var/lib/mysql/"
}
old_db_path () {
printf "%s%s/" "$(mysql_path)" "$OLD_DB"
}
new_db_path () {
printf "%s%s/" "$(mysql_path)" "$NEW_DB"
}
get_tables () {
(Sudo find /var/lib/mysql/$OLD_DB -name "*.frm" -printf "%f\n") | cut -d'.' -f1 | sort
}
STEP=0
authenticate () {
printf "\e[0;104m"
Sudo ls &> /dev/null
printf "\e[0m"
echonotice 'Authenticated.'
}
echostep $((++STEP))
authenticate
TABLE_COUNT=`get_tables | wc -l`
SPACE_AVAIL=`df -k --output=avail $(mysql_path) | tail -n1`
SPACE_NEEDED=(`Sudo du -s $(old_db_path)`)
SPACE_ERR=`echo "$SPACE_AVAIL-$SPACE_NEEDED" | bc`
SPACE_WARN=`echo "$SPACE_AVAIL-$SPACE_NEEDED*3" | bc`
if [ $SPACE_ERR -lt 0 ]; then
echoerror 'There is not enough space to branch the database.'
echoerror 'Please free up some space and run this command again.'
SPACE_AVAIL_FORMATTED=`printf "%'d" $SPACE_AVAIL`
SPACE_NEEDED_FORMATTED=`printf "%'${#SPACE_AVAIL_FORMATTED}d" $SPACE_NEEDED`
echonotice "$SPACE_NEEDED_FORMATTED bytes needed to create database branch"
echonotice "$SPACE_AVAIL_FORMATTED bytes currently free"
exit 1
Elif [ $SPACE_WARN -lt 0 ]; then
echowarn 'This action will use more than 1/3 of your available space.'
SPACE_AVAIL_FORMATTED=`printf "%'d" $SPACE_AVAIL`
SPACE_NEEDED_FORMATTED=`printf "%'${#SPACE_AVAIL_FORMATTED}d" $SPACE_NEEDED`
echonotice "$SPACE_NEEDED_FORMATTED bytes needed to create database branch"
echonotice "$SPACE_AVAIL_FORMATTED bytes currently free"
printf "\e[0;104m"
read -p " $(now): Do you still want to branch the database? [y/n] " -n 1 -r CONFIRM
printf "\e[0m"
echo
if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
echonotice 'Database was NOT branched'
exit 1
fi
fi
PASS='badpass'
connect_to_db () {
printf "\e[0;104m %s: MySQL root password: \e[0m" "$(now)"
read -s PASS
PASS=${PASS:-badpass}
echo
echonotice "Connecting to MySQL..."
}
create_db () {
echonotice 'Creating empty database...'
echo "CREATE DATABASE \`$NEW_DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" | mysql -u root -p$PASS 2>> $(tmp_file 'errors.log')
DB_CREATED=true
}
build_tables () {
echonotice 'Retrieving and building database structure...'
mysqldump $OLD_DB --skip-comments -d -u root -p$PASS 2>> $(tmp_file 'errors.log') | pv --width 80 --name " $(now)" > $(tmp_file 'dump.sql')
pv --width 80 --name " $(now)" $(tmp_file 'dump.sql') | sql_on_new_db
}
set_debug_1 () {
echonotice 'Switching into recovery mode for innodb...'
printf '[mysqld]\ninnodb_file_per_table = 1\ninnodb_force_recovery = 1\n' | Sudo tee $MYSQL_CNF_PATH > /dev/null
}
set_debug_0 () {
echonotice 'Switching out of recovery mode for innodb...'
Sudo rm -f $MYSQL_CNF_PATH
}
discard_tablespace () {
echonotice 'Unlinking default data...'
(
echo "USE \`$NEW_DB\`;"
echo "SET foreign_key_checks = 0;"
get_tables | while read -r line;
do echo "ALTER TABLE \`$line\` DISCARD TABLESPACE; SELECT 'Table \`$line\` imported.';";
done
echo "SET foreign_key_checks = 1;"
) > $(tmp_file 'discard_tablespace.sql')
cat $(tmp_file 'discard_tablespace.sql') | sql_on_new_db | pv --width 80 --line-mode --size $TABLE_COUNT --name " $(now)" > /dev/null
}
import_tablespace () {
echonotice 'Linking imported data...'
(
echo "USE \`$NEW_DB\`;"
echo "SET foreign_key_checks = 0;"
get_tables | while read -r line;
do echo "ALTER TABLE \`$line\` IMPORT TABLESPACE; SELECT 'Table \`$line\` imported.';";
done
echo "SET foreign_key_checks = 1;"
) > $(tmp_file 'import_tablespace.sql')
cat $(tmp_file 'import_tablespace.sql') | sql_on_new_db | pv --width 80 --line-mode --size $TABLE_COUNT --name " $(now)" > /dev/null
}
stop_mysql () {
echonotice 'Stopping MySQL...'
Sudo /etc/init.d/mysql stop >> $(tmp_file 'log')
}
start_mysql () {
echonotice 'Starting MySQL...'
Sudo /etc/init.d/mysql start >> $(tmp_file 'log')
}
restart_mysql () {
echonotice 'Restarting MySQL...'
Sudo /etc/init.d/mysql restart >> $(tmp_file 'log')
}
copy_data () {
echonotice 'Copying data...'
Sudo rm -f $(new_db_path)*.ibd
Sudo rsync -ah --info=progress2 $(old_db_path) --include '*.ibd' --exclude '*' $(new_db_path)
}
give_access () {
echonotice "Giving MySQL user \`$USER\` access to database \`$NEW_DB\`"
echo "GRANT ALL PRIVILEGES ON \`$NEW_DB\`.* to $USER@localhost" | sql_on_new_db
}
echostep $((++STEP))
connect_to_db
EXISTING_TABLE=`echo "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$NEW_DB'" | mysql --skip-column-names -u root -p$PASS 2>> $(tmp_file 'errors.log')`
if [ "$EXISTING_TABLE" == "$NEW_DB" ]
then
echoerror "Database \`$NEW_DB\` already exists"
exit 1
fi
echoinstructions "The hamsters are working. Check back in 5-10 minutes."
sleep 5
echostep $((++STEP))
create_db
echostep $((++STEP))
build_tables
echostep $((++STEP))
set_debug_1
echostep $((++STEP))
discard_tablespace
echostep $((++STEP))
stop_mysql
echostep $((++STEP))
copy_data
echostep $((++STEP))
start_mysql
echostep $((++STEP))
import_tablespace
echostep $((++STEP))
set_debug_0
echostep $((++STEP))
restart_mysql
echostep $((++STEP))
give_access
echo
echosuccess "Database \`$NEW_DB\` is ready to use."
echo
trap general_cleanup EXIT
Si tout se passe bien, vous devriez voir quelque chose comme:
En plus de la réponse de Greg.
le moyen le plus simple et le plus rapide si le new_db_name
n'existe pas encore.
echo "create database new_db_name" | mysql -u <user> -p <pwd>
mysqldump -u <user> -p <pwd> db_name | mysql -u <user> -p <pwd> new_db_name
Si vous avez des déclencheurs dans votre base de données d'origine, vous pouvez éviter l'erreur "Le déclencheur existe déjà" en envoyant un remplacement avant l'importation:
mysqldump -u olddbuser -p -d olddbname | sed "s/`olddbname`./`newdbname`./" | mysql -u newdbuser -p -D newdbname
Je ne pense pas qu'il existe une méthode pour faire cela. Lorsque cela est fait, PHPMyAdmin vide la base de données puis la réinsère sous le nouveau nom.
Utilisez 'mysqldbcopy' sur le terminal. Ce cas est bien mentionné ici ..__ Exemple: Démarrez l’invite cmd. Accédez au dossier bin de mySql Server. Lancez la requête ci-dessous:
C:\Program Files\MySQL\MySQL Server 5.7\bin>mysqldbcopy --source=root:root@localhost --destination=root:root@localhost master:master_clone
ici, j'essaie de copier ma base de données «master» sur «master_clone» sur localhost.