হিসাবে উল্লেখ গ্রেগ এর উত্তর , mysqldump db_name | mysql new_db_name
হয় , মুক্ত নিরাপদ, এবং সহজ ডাটাবেস মধ্যে ডেটা স্থানান্তর করতে উপায়। যাইহোক, এটি সত্যিই ধীর ।
আপনি যদি ডেটা ব্যাকআপের সন্ধান করছেন, ডেটা হারাতে পারবেন না (এই বা অন্যান্য ডাটাবেসে), বা অন্য কোনও সারণী ব্যবহার করছেন innodb
, তবে আপনার ব্যবহার করা উচিত mysqldump
।
আপনি যদি বিকাশের জন্য কিছু সন্ধান করেন, আপনার সমস্ত ডাটাবেস অন্য কোথাও ব্যাক আপ করে রাখুন এবং mysql
সবকিছু ভুল হয়ে যাওয়ার পরে বিশুদ্ধ করতে এবং পুনরায় ইনস্টল করা (সম্ভবত ম্যানুয়ালি) স্বাচ্ছন্দ্য বোধ করেন তবে আমার কাছে কেবল সমাধান হতে পারে।
আমি একটি ভাল বিকল্প খুঁজে পাইনি, তাই আমি নিজে এটি করার জন্য একটি স্ক্রিপ্ট তৈরি করেছি। প্রথমবারের মতো কাজ করার জন্য আমি অনেক সময় ব্যয় করেছি এবং এখনই এটিতে পরিবর্তন আনতে এটি সত্যই আমাকে ভীত করে। ইনোডব ডাটাবেসগুলি এর আগে অনুলিপি করা এবং আটকানো নয়। ছোট পরিবর্তনগুলির কারণে এটি দুর্দান্ত পদ্ধতিতে ব্যর্থ হয়। কোডটি চূড়ান্ত করার পর থেকে আমার কোনও সমস্যা হয়নি, তবে এর অর্থ এই নয় যে আপনি করবেন না।
সিস্টেমগুলি পরীক্ষিত হয়েছে (তবে এখনও এটি ব্যর্থ হতে পারে):
- উবুন্টু 16.04, ডিফল্ট মাইএসকিএল, ইনানোডবি, প্রতি টেবিলের জন্য পৃথক ফাইল
- উবুন্টু 18.04, ডিফল্ট মাইএসকিএল, ইনানোডবি, প্রতি টেবিলের জন্য পৃথক ফাইল
এর মানে কি
sudo
বিশেষাধিকার পায় এবং আপনার কাছে ডাটাবেস ক্লোন করার পর্যাপ্ত সঞ্চয় স্থান রয়েছে যাচাই করে
- রুট মাইএসকিএল সুবিধাগুলি পান
- বর্তমান গিট শাখার নামে একটি নতুন ডাটাবেস তৈরি করে
- নতুন ডাটাবেসে ক্লোনগুলির কাঠামো
- ইনোনডাবের জন্য পুনরুদ্ধার মোডে স্যুইচ করে
- নতুন ডাটাবেসে ডিফল্ট ডেটা মুছে দেয়
- বন্ধ করে দেয় mysql
- নতুন ডাটাবেসে ক্লোনস ডেটা
- মাইএসকিএল শুরু হয়
- লিঙ্কগুলি নতুন ডাটাবেসে ডেটা আমদানি করে
- ইনোনডাবের জন্য পুনরুদ্ধার মোডের বাইরে চলে যায়
- মাইএসকিএল পুনরায় চালু করুন
- Mysql ব্যবহারকারীকে ডাটাবেসে অ্যাক্সেস দেয়
- অস্থায়ী ফাইলগুলি পরিষ্কার করে
এর সাথে কীভাবে তুলনা করা যায় mysqldump
3 জিবি ডাটাবেসে ব্যবহার করে mysqldump
এবং mysql
আমার মেশিনে 40-50 মিনিট সময় লাগবে। এই পদ্ধতিটি ব্যবহার করে, একই প্রক্রিয়াটিতে কেবল ~ 8 মিনিট সময় লাগবে।
আমরা এটি কীভাবে ব্যবহার করি
আমাদের কোডের পাশাপাশি আমাদের এসকিউএল পরিবর্তনগুলি সংরক্ষণ করা হয়েছে এবং আপগ্রেড প্রক্রিয়াটি ত্রুটি থাকলে পুনরুদ্ধার করতে ডাটাবেসটির ব্যাকআপ তৈরি করে প্রতিটি সেট পরিবর্তনের সাথে সাথে উত্পাদন এবং বিকাশ উভয় ক্ষেত্রেই স্বয়ংক্রিয় হয়। আমরা যখন সমস্যার সমাধান করেছি তখন হ'ল আমরা যখন ডাটাবেস পরিবর্তন নিয়ে দীর্ঘমেয়াদী প্রকল্পে কাজ করছিলাম এবং বাগ বা তিনটি ঠিক করার জন্য এর মাঝখানে শাখাগুলি স্যুইচ করতে হয়েছিল।
অতীতে, আমরা সমস্ত শাখার জন্য একটি একক ডাটাবেস ব্যবহার করতাম এবং যখনই আমরা একটি শাখায় স্যুইচ করেছিলাম যা নতুন ডাটাবেস পরিবর্তনের সাথে সামঞ্জস্যপূর্ণ ছিল না তখন ডাটাবেসটিকে পুনর্নির্মাণ করতে হবে। এবং আমরা যখন আবার স্যুইচ করেছি, আমাদের আবারও আপগ্রেডগুলি চালাতে হবে।
আমরা mysqldump
বিভিন্ন শাখার জন্য ডাটাবেসটিকে নকল করার চেষ্টা করেছি , তবে অপেক্ষা করার সময়টি খুব দীর্ঘ (40-50 মিনিট) ছিল এবং আমরা এর মধ্যে আর কিছু করতে পারি নি।
এই সমাধানটি ডাটাবেস ক্লোনের সময়কে 1/5 বার সংক্ষিপ্ত করে রেখেছিল (দীর্ঘ লাঞ্চের পরিবর্তে কফি এবং বাথরুম বিরতি ভাবেন)।
সাধারণ কাজ এবং তাদের সময়
অসামঞ্জস্য ডাটাবেস পরিবর্তনের সাথে শাখাগুলির মধ্যে স্যুইচ করাতে একটি একক ডাটাবেসে 50+ মিনিট সময় লাগে তবে প্রাথমিক কোডআপের পরে mysqldump
বা এই কোডটির পরে মোটেই সময় লাগে না । এই কোডটি এর চেয়ে 5 গুন বেশি দ্রুত হতে পারে mysqldump
।
এখানে কয়েকটি সাধারণ কাজ এবং প্রতিটি পদ্ধতিতে তারা কত সময় নিবে তা এখানে:
ডাটাবেস পরিবর্তন সহ বৈশিষ্ট্য শাখা তৈরি করুন এবং ততক্ষনে মার্জ করুন:
- একক ডাটাবেস: 5 মিনিট
- সাথে ক্লোন করুন
mysqldump
: 50-60 মিনিট
- এই কোডটি দিয়ে ক্লোন করুন: minutes 18 মিনিট
ডাটাবেস পরিবর্তন সহ বৈশিষ্ট্য শাখা তৈরি করুন, master
বাগফিক্সের জন্য স্যুইচ করুন, বৈশিষ্ট্য শাখায় একটি সম্পাদনা করুন এবং মার্জ করুন:
- একক ডাটাবেস: ~ 60 মিনিট
- সাথে ক্লোন করুন
mysqldump
: 50-60 মিনিট
- এই কোডটি দিয়ে ক্লোন করুন: minutes 18 মিনিট
ডাটাবেস পরিবর্তন সহ বৈশিষ্ট্য শাখা তৈরি করুন, master
অন্তর্নির্মিত বৈশিষ্ট্য শাখায় সম্পাদনা করার সময় একটি বাগফিক্সের জন্য 5 বার স্যুইচ করুন এবং মার্জ করুন:
- একক ডাটাবেস: hours 4 ঘন্টা, 40 মিনিট
- সাথে ক্লোন করুন
mysqldump
: 50-60 মিনিট
- এই কোডটি দিয়ে ক্লোন করুন: minutes 18 মিনিট
কোড
আপনি উপরের সমস্ত কিছু না পড়ে এবং বুঝতে না পারলে এটি ব্যবহার করবেন না।
#!/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
যদি সবকিছু সুষ্ঠুভাবে চলে যায় তবে আপনার এমন কিছু দেখা উচিত: