MySQL_DBA整理

分類: Mysql/postgreSQLphp

 

 

轉自:丁丁:http://www.itpub.net/thread-831154-2-1.htmlhtml

 mysql_dba_備份與還原部分介紹.doc (72 KB) mysql

MySQL_DBA整理sql

前言數據庫

       幾乎全部的資料整理都在Linux系統、mySQL5.0.27版本和MyISAM存儲引擎環境下試驗和總結的,以及參考前人經驗與MySQL官網資料進行總結的。關於MySQL 的安裝與升級,我相信不少MySQL_DBA都比我厲害,MySQL官網與其餘網站上應該有不少相關資料:bash

         關於安裝寫一條簡單的命令與一些必要的說明:app

         1. 源碼安裝的腳本ide

./configure --prefix=/usr/local/mysql --with-mysqld-user=mysql --with-charset=gb2312 --with-extra-charsets=all函數

       因爲個人數據庫只使用gb2312,因此爲了一致性就這樣設置,你也能夠設置爲本身的類型。工具

         2.必要說明:

         爲了方便程序的升級以及性能更高,應該把MySQL程序與數據文件放在不一樣的目錄下面,最好仍是不一樣的磁盤上。若起用了日誌功能,最好是把MySQL程序、數據文件和日誌文件分別放在三個不一樣的磁盤上,從而避免程序升級帶來的潛在而致命的問題,提升數據的讀寫能力(注:畢竟磁盤的轉速有限)。

第一部分:數據庫的備份與還原

      對於MyISAM 存儲引擎的表,因爲只有表級的鎖,因此目前尚未出現象InnoDB存儲引擎的那種能夠不縮定表的備份方法。目前用得最多最廣泛的兩種方法:文件的拷貝與dump數據庫。

       文件的拷貝:就是在備份期間鎖定數據庫表,不容許其餘用戶進行任何更新操做,而後直接把*.MYD

、*MYI、db.opt文件拷貝到備份的目錄下。通常使用免費的工具:mysqlhotcopy,至於如何使用會在備份腳本中給出參考,可是該方法沒有辦法備份存儲過程、函數等,可是另系統庫(mysql)一塊兒備份的話,是能夠實現備份存儲過程、函數等的效果。

       Dump方法:也是很是相似,就是把指定數據庫的全部數據表結構與數據生成Create 與Insert語句。

       總結:這兩種方法各有優劣,須要看根據實際狀況使用那種備份方法。

       1>、文件拷貝:此方法備份的速度快,鎖定表的時間相對短,且恢復起來也很是快。可是恢復的時候,通常須要在同一種類型的系統、MySQL版本上進行恢復備份的數據庫文件。缺少跨平臺的、跨版本等缺點。

       2>、Dump:此方法備份的速度慢,鎖定表的時間長,且恢復起來也慢。但是此種備份的文件,具備跨平臺、跨版本、跨存儲引擎(備份時設置好就能夠)等優點。

       介於上面的描述,咱們應該是兩種方法結合。好比:平時進行完整備份時,能夠採用文件拷貝的方式;對於備份的文件須要放到不一樣類型系統平臺的或不一樣 MySQL版本上再進行還原話,建議採用Dump方式。建議以上兩種備份方式能夠只做爲完整備份的方式,若須要精確到秒的話,能夠考慮:

文件拷貝+日誌備份 或Dump+日誌備份,最好是採用文件拷貝+日誌備份。至於備份的頻率,須要根據本身的系統特色與數據重要指定。在此介紹一種比較廣泛的策略:

       天天的05:00:00左右進行完整備份,而後每小時進行一第二天志文件備份。(注意:日誌文件太大的話,使用MySQL客戶端工具進行重作的話,會比較慢)。

 

下面給出完使用mysqlhotcopy工具有份與自動還原的代碼:

完整備份:

#!/bin/bash

#First,create direct /back

# setting servername

server=test

 

#the directory of backup

backdir=/back/mysql

 

#use log file record log

logfile=$backdir/mysqlbak.log

 

today=`date +%y-%m-%d`

todaydir=$server-$today

backup=$backdir/$todaydir

 

#the password of mysql

rootpass=123456a

dbname=eugene

 

#remake the directory of backup

if [ ! -d $backdir ] ; then

   mkdir $backdir

else

   chattr -i $backdir

fi

 

cd $backdir

 

if [ ! -f $logfile ] ; then

    touch $logfile

else

    chattr -i $logfile

fi

 

echo "             " >> $logfile

echo "fully backup starting!" >> $logfile

echo $(date +"%y%m%d %h:%m%s") >> $logfile

echo "             " >> $logfile

 

mkdir $backup

 

#backup with database

/usr/local/mysql/bin/mysqlhotcopy $dbname --flushlog -u admin -p $rootpass $backup | logger -t mysqlhotcopy

 

echo "fully backup database success!" >> $logfile

 

#compress backup file and deleted unregimented file

cd $backdir

tar -zcf $todaydir.tgz $todaydir/$dbname/

rm -rf $todaydir

 

#cd $backdir

#Keep Down Thirty Days

for f in `find . -type f -mtime +30 -maxdepth 1`

do

 filename=`basename $f`

 #can't deleted log file

 if [ $f != 'mysqlbak.log' ] ; then

    rm -fr $f

 fi

done

#add property

chattr +i $backdir

 

 

日誌備份:

#!/bin/bash

#everyday and hourly backup log files once

#setting server's name

server=test

#log files's directory

logfile=/usr/local/mysql/var

#the directory of backup

backdir=/back/increment

hourly=`date +"%y-%m-%d-%H-%M-%S"`

today=`date +%y-%m-%d`

todaydir=$backdir/$server-$today

hourlydir=$server-$hourly

backupdir=$todaydir/$hourlydir

rootpass=123456a

#create directory ,but back is exist

#increment is exist or bot exist,General,first It need creatting

if [ ! -d $backdir ] ; then

   mkdir $backdir

else

   chattr -i $backdir

fi

#judge today directory is exist or not exist

if [ ! -d $todaydir ] ; then

    mkdir $todaydir

else

    chattr -i $todaydir

fi

#create directory is using storage log files

mkdir $backupdir

#execute flush logs

/usr/local/mysql/bin/mysqladmin -u admin -p$rootpass flush-logs

#stat mysql-bin log file total, throw off lastly and mysql-bin.index

total1=`ls $logfile/mysql-bin.*|wc -l`

total=$(expr $total1 - 2)

for f in `ls $logfile/mysql-bin.*|head -n $total`

do

  mv $f $backupdir

done

#compress log files

cd $todaydir

#Because file'name include mark of : ,it will make a mistake,So we dispart two-step complete

tar -zcf $hourlydir.tgz $hourlydir/

rm -rf $hourlydir

#deleted overdue files and directs

cd $backdir

#Keep Down Thirty Days;deleted *.tgz file

for d in `find . -type d -mtime +30 -maxdepth 1`

do

  #filename=`basename $f`

  rm -fr $d

done

# alter file and directory  property

chattr +i $backdir

 

 

 

 

 

 

 

 

 

 

自動還原:

#!/bin/bash

#this is restore database script

#author:eugene

#date:2007-07-26

#***************Define Begin***************************#

#fully backup database file directory

fulldir=/back/mysql

#increment backup log file directory

incrementdir=/back/increment

#it is mysqlbinlog's directory

bindir=/usr/local/mysql/bin

vardir=/usr/local/mysql/var

para=07-08-15

time=04

 

#setting fully backup database at 05:30

backuptime=05

#databse'sname

dbname=eugene

#root's password

passwrd=123456a

#log file's name

logfile=mysql-bin

 

#*************** Define End ***************************#

 

#*************** Function Start************************#

#parameter: yy-mm-dd

#return: max(day)

mon_max_day()

{

 day=0

#Because parameter of date's format yy-mm-dd,so we must convert to yyyy-mm-dd

 year=$( expr $2 + 2000 )

 if [ $1 -gt 0 -a $1 -lt 13 ]; then

    case $1 in

              1|01|3|03|5|05|7|07|8|08|10|12) day=31;;

              4|04|6|06|9|09|11) day=30;;

              2|02)

                  if [ `expr $year % 4` -eq 0 ] ; then

                        if [ `expr $year % 400` -eq 0 ] ; then

                                day=29

                        elif [ `expr $year % 100` -eq 0 ] ; then

                                day=28

                        else

                                day=29

                        fi

                   else

                        day=28

                   fi

    esac

fi

echo $day

}

 

#usage: get discretionary date's yesterday date,parameter:yy-mm-dd

#return: yy-mm-dd

yesterday()

{

 num=$1

 year=$(echo $num|awk -F- '{print $1}')

 month=$(echo $num|awk -F- '{print $2}')

 day=$(echo $num|awk -F- '{print $3}')

 

 day=$(expr $day - 1)

 if [ $day -eq 0 ] ; then

    month=$(expr $month - 1)

 

    if [ $month -eq 0 ] ; then

       year=$(expr $year - 1)

       month=12

    fi

 

    day=$(mon_max_day $month $year)

    value=$year-$month-$day

 

 else

    value=$year-$month-$day

 fi

 echo $value

}

 

#parameter: $1---yy-mm-dd; $2---0 or 1 or 2 or 3; $3---fulldir;$4---vardir

#0---copy current day's file,

#1---copy yesterday day's file

#2---copy last month day's file

#3---copy last year day's file

 

fullycp()

{

  strdate=$1

  num=$2

  fullydir=$3

  vardir=$4

 

  year=$(echo $strdate | awk -F- '{print $1}') #create directory's year

  month=$(echo $strdate | awk -F- '{print $2}') #create directory's  month

  day=$(echo $strdate | awk -F- '{print $3}') #create directory's day

 

  case $num in

              0) ;;

              1|2|3) strdate=$(yesterday $strdate)

                     year=$(echo $strdate | awk -F- '{print $1}') #create directory's year

                     month=$(echo $strdate | awk -F- '{print $2}') #create directory's  month

                     day=$(echo $strdate | awk -F- '{print $3}') #create directory's day

                 ;;

    esac

 

 for f in `ls $fullydir`

     do

        #if [ -d $fullydir/$f ] ; then

         filename=`basename $f`

         if [ $filename!='mysqlbak.log' ] ; then   #test catalog include mysqlbak.log,so filt the file

 

           num1=$(echo $f | awk -F- '{print $2}') #create directory's year

           num2=$(echo $f | awk -F- '{print $3}') #create directory's  month

           num4=$(echo $f | awk -F- '{print $4}') #create directory's day.tgz

           num3=$(echo $num4 | awk -F. '{print $1}') #create directory's day

 

           if [ $year -eq $num1 -a $month -eq $num2 -a $day -eq $num3 ] ; then

               echo "success!"

               tar zxvf $f

               cp -rf $fullydir/$f/$dbname $vardir

           fi

        fi

    done

}

 

#*************** Function End************************#

#alter back/increment directory attribute

chattr -i $incrementdir

 

year=$(echo $para | awk -F- '{print $1}')

month=$(echo $para | awk -F- '{print $2}')

day=$(echo $para | awk -F- '{print $3}')

 

#shutdown mysql service

#Judge mysqld is running or stopping

#for d in `ps -e|grep mysql|awk '{ print $4 }'`

#do

#  if [ $d == 'mysqld' ] ; then

#     #/etc/init.d/mysql stop

#   fi

#done

 

if [ $backuptime  -lt $time ] ; then  #05 < time

  

  #deal with fully backup files with  transfer function fullycp($strdate $flag $fulldir $vardir)

  fullycp $para 0 $fulldir $vardir

  

  #deal with log files

  for f1 in `ls $incrementdir`

     do

       num1=$(echo $f1 | awk -F- '{print $2}') #create directory's year

       num2=$(echo $f1 | awk -F- '{print $3}') #create directory's  month

       num3=$(echo $f1 | awk -F- '{print $4}') #create directory's day

      

       if [ -d $incrementdir/$f1 ] ; then  #judge target is file or director

 

        if [ $year -eq $num1 -a $month -eq $num2 -a $day -eq $num3 ] ; then

                 for f2 in `ls $incrementdir/$f1`

                 do

                   bf2=$(echo $f2 | awk -F: '{print $1}')

                   bf3=$(echo $bf2 | awk -F- '{print $5}')

 

                  if [ $bf3 -le $time ] ; then   #bf3 <= time

                     for f4 in `ls $incrementdir/$f1/$f2/$logfile.*|head`

                         do

                          $bindir/mysqlbinlog --database=$dbname $f4 >> $incrementdir/test.sql

                         done

                   fi

                  done

            fi

         fi

      done

else

#Because fully backup event is happened in 05:30,so use yesterday's fully backup ,

#and deal with yesterday's log file and intraday's log files

#don't consider restore every month's first day ,must be considered

 

   #deal with yesterday's fully backup files with  transfer function fullycp($strdate $flag $fulldir $vardir)

   fullycp $para 1 $fulldir $vardir

   

    curryear=$(echo $para | awk -F- '{print $1}')

    currmonth=$(echo $para | awk -F- '{print $2}')

    currday=$(echo $para | awk -F- '{print $3}')

  

   #get the current's date of yesterday's date  

   lastdate=$(yesterday $para)

 

   lastyear=$(echo $lastdate | awk -F- '{print $1}')

   lastmonth=$(echo $lastdate | awk -F- '{print $2}')

   lastday=$(echo $lastdate | awk -F- '{print $3}')

 

     

    #need deal with currently and yesterday log files

 

        #first,deal with year-mm-(day - 1)'s log files

        for f1 in `ls $incrementdir`

           do

             if [ -d $incrementdir/$f1 ] ; then  #judge target is file or director

                num1=$(echo $f1 | awk -F- '{print $2}') #create directory's year

                num2=$(echo $f1 | awk -F- '{print $3}') #create directory's  month

                num3=$(echo $f1 | awk -F- '{print $4}') #create directory's day

                

                       

                if [ $lastyear -eq $num1 -a $lastmonth -eq $num2 -a $lastday -eq $num3 ] ; then

                   for f2 in `ls $incrementdir/$f1`

                     do

                       bf2=$(echo $f2 | awk -F: '{print $1}')

                       bf3=$(echo $bf2 | awk -F- '{print $5}')

 

                       if [ $bf3 -ge $backuptime ] ; then   #bf3 >= backuptime or backuptime - 1

                          for f4 in `ls $incrementdir/$f1/$f2/$logfile.*|head`

                             do

                               $bindir/mysqlbinlog --database=$dbname $f4 >> $incrementdir/test.sql

                         done

                       fi

                     done

                 elif [ $curryear -eq $num1 -a $currmonth -eq $num2 -a $currday -eq $num3 ] ; then

                      for f2 in `ls $incrementdir/$f1`

                        do

                           bf2=$(echo $f2 | awk -F: '{print $1}')

                           bf3=$(echo $bf2 | awk -F- '{print $5}')

 

                         if [ $bf3 -le $time ] ; then  #bf3 <=time

                            for f4 in `ls $incrementdir/$f1/$f2/$logfile.*|head`

                             do

                               $bindir/mysqlbinlog --database=$dbname $f4 >> $incrementdir/test.sql

                             done 

                          fi

                        done

                  fi

               fi

             done      

fi

 

if [ -f $incrementdir/test.sql ] ; then

   sed '/^ROLLBACK/ d' $incrementdir/test.sql > $incrementdir/template.sql

else

   echo "don't exist backup database files!"

   exit

fi

#start mysql service

#must copy mysql.mysql to /etc/init.d/mysql

#/etc/init.d/mysql start

/usr/local/mysql/bin/mysql -uadmin -p$passwrd $dbname < $incrementdir/template.sql

rm $incrementdir/test.sql

rm $incrementdir/template.sql

#add /back/increment directory attribute

chattr +i $incrementdir

對此申明下:本人的Shell腳本屬於現學現賣的那種,我知道這些腳本確定能夠寫得更簡單,其實我寫的自動還原的腳本是一種特殊狀況下用的。。。好比有N 多天前的完整備份存在問題,而只有N+1條的完整備份是無缺的,因此須要使用N+1前天的完整備份再加上N+1 條到目前的日誌完整,若N>=2條的話,日誌就有不少了,手工還原就麻煩,這個腳本就有用了。

       對於遊戲、金融等行業須要只針對某個賬號的信息進行回檔處理,在MySQL5.0及以上的版本就很是容易了,只要根據須要回檔的時間,就可使用此時間段的日誌文件進行回檔,二進制日誌翻譯的語句以下:

usr/local/mysql/bin/mysqlbinlog –start_datetime=」2007-10-29 05:21:00」 –stop_datetime=」 2007-10-29 05:25:00 」 eugene.01831 > mysql –uroot –p Eugene

解釋下:只要須要翻譯某段時間之間的二進制的日誌,能夠指定start_datetime與stop_datetime,不指定則是把eugene.01831日誌文件所有翻譯成SQL語句而且經過mysql客戶端工具執行,eugene爲指定在那個數據庫上執行生成的SQL語句。

      以遊戲行業恢復某個玩家角色的物品爲例解釋下,可能會比較好理解。假設A 玩家在2007-10-29 03:24:00至 2007-10-29 03:29:00之間出現裝備丟失。

        若update語句的where 條件是根據角色的編號ID,咱們能夠先根據角色名稱找到對應的ID(社爲1001),而後再執行:

usr/local/mysql/bin/mysqlbinlog –start_datetime=」 2007-10-29 03:24:00」 –stop_datetime=」 2007-10-29 03:29:00 」 eugene.01832 > Eugene.sql,再把eugene.sql放到eugene.doc文檔中查找下ID=1001的update角色表的語句,複製出來並稍微修改下再利用客端 執行下修改後的update語句就能夠實現只更改裝備的數據了。

相關文章
相關標籤/搜索