mysql刪除數據庫的過程


在dba圈混跡很久了,早早就想寫點博客,總結一些經驗什么的,總是因為時間少呀,人懶呀,覺得文筆不好呀啥雜七雜八原因,一直很少寫點東西,

不過前幾天和一朋友討論了一下刪庫的過程,我覺得挺有意思,

准備記錄一下。

 

有刪庫需求情況挺多,比如有一天項目結束了需要,開發說要刪除這個數據庫。也許機器磁盤不夠了,上面正好有一個很大的庫,但是好像又沒用,刪除可以釋放資源,比如某一天你突然覺得這個沒有的庫放在那里肯礙眼,想刪除它,

當然也有可能是業務需求,會經常創建和刪除庫 等等情況, 其實說明 刪庫這個需求確認真實存在的。

 

也許你會覺得刪庫這個問題很簡單,一個命令而已,  drop database db_name; 是不是很簡單。

 

我們刪除屬於DDL操作,不能回滾數據,如果需要恢復,那基本需要全量備份+binlog,

影響恢復時間的因素很多: 恢復決策的時間,dba恢復數據熟練度,實例大小,數據修改頻繁度,以及機器配置,網絡傳輸速度 和其他因素

而且不管怎么說,如果刪除的數據庫,里面還有業務訪問,影響業務是肯定,不能快速恢復也是很蛋疼的事兒。

所以我需要做的就是,盡量減少刪除后需要恢復的可能性。

我們需要考慮的情況比較多,

下面列舉一部分常見,其他根據不同場景大家可以自己考慮考慮,也是一個總結的過程哇

一、開發或者業務提出要刪庫:

1、開發提出需要刪除 某某庫,db應該需要確認該庫是否可以刪除

     a)、如果程序使用了長連接,我們可以先看看是否有該庫的連接,如果有該庫的連接,直接駁回,讓開發確認程序是否下線完成。可以使用下面語句確認。

    select * from information_schema.processlist where DB='$db_name';

     b)、如果檢查未發現長連接,則需要查看是否有短連接的程序訪問:如果有訪問依舊需要找開發確認,如果沒有訪問,有條件可以多觀察一段時間。

   可以借助簡單的工具 mysql-sniffer :

        ./mysql-sniffer -i bond0 -p 6006  |grep "$db_name"   ,可以獲取到訪問ip,庫名,sql語句等,通過grep工具過濾可以得到很小的結果集,使用非常方便。

         項目為360開源項目:https://github.com/Qihoo360/mysql-sniffer,當然也可以使用tcpdump,開啟general_log 的方式來做。辦法有很多種

    c)、已經確認確實程序已經沒有使用程序訪問該庫,我們就需要開了刪庫了,

          方案1、先remoke 該庫相關的權限,然后觀察一段時間,如果沒有問題就可以刪庫。

                     優點:就是以后建立同名庫,不存在權限問題,

                     缺點:如果考慮操作回滾,需要備份數據庫的權限,最好還只能備份被remoke的權限,這個過程其實不好做,考慮的因素挺多。

          方案2、不remoke 權限,直接rename 數據庫名,原理是先建立一個新庫,將需要重命名的庫里面的表全部通過RENAME TABLE tbl_name TO new_tbl_name的方式將表放入新的庫里面,

                     然后將老庫刪除。需要注意,新老庫要放在同一個磁盤分區里面,不然效率會特別低,這個過程使整個實例hang住,后果很嚴重。

                    優點:不用做任何單獨備份任何東西,回滾非常方便。

                    缺點:考慮同名庫權限問題,還是需要回收相關的權限,由於我們沒有同名數據庫的問題,所以權限並未回收。

       個人傾向方案2,簡單好實施,並且有簡單的腳本:

#!/bin/sh
function executeSql()
{
    sql="$1"

    if [ "$sql" = "" ]
    then
        cat | mysql --default-character-set=utf8 -N 
    else
        echo "$sql" | mysql --default-character-set=utf8 -N 
    fi
}



function mysqlDBRename()
{
        
        tempFromDBName="${fromDBName}"
        tempToDBName="${toDBName}"
        #建庫
        echo "create database ${toDBName};" | executeSql
        if [ "$?" -ne 0 ]; then
                echo "Error: Some error occur when create database ${toDBName}."
                exit 0
        fi

        echo "select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='$fromDBName' and TABLE_TYPE='BASE TABLE';" | executeSql | while read tableName; do
                echo "alter table ${fromDBName}.${tableName} rename ${toDBName}.${tableName};" | executeSql
                if [ "$?" -ne 0 ]; then
                        echo "Error: Some error occur when execute 'alter table ${fromDBName}.${tableName} rename ${toDBName}.${tableName};'"   
                        exit 1
                fi
        done
        if [ "$?" -ne 0 ]; then
                exit 0
        fi
    
        echo "drop database ${fromDBName}" | executeSql
        if [ "$?" -ne 0 ]; then
               echo "Error: Some error occur when drop database ${fromDBName}."
               exit 1
        fi
        break

}


function main()
{
        fromDBName="$1"
        toDBName="$2"
        mysqlDBRename
}
main "$1" "$2" 

 

  d)、刪庫;

         當步驟c做了一段時間,比如1周,確認程序已經完全下了后。

   1、如果該實例上面沒有其他的實例,則可以直接將實例shutdown,刪除實例,將最后一個備份文件歸檔,整個過程就算完成

           2、如果該實例還有其他業務正在使用,則還需要考慮更多問題:

                 需要刪除是庫是否很大,是否有很多數量的表,比如超過1000張表,如果磁盤性能不夠好,可能會對線上查詢元數據的操作阻塞,例如:使用了存儲過程,那么都會阻塞在讀取存儲過程這個步驟。

                 因此建議 1、分批次刪除表,

         2、如果有大量分區的分區表,建議先刪除分區。

                               我這有一個存儲過程可以做這個事兒,前提是需要將dbman rename成 del_xxxx這種格式的。在需要刪除分區的庫里面創建該存儲過程,然后調用存儲過程就可以。

DELIMITER $$

DROP PROCEDURE IF EXISTS `droppartion_del`$$

CREATE  PROCEDURE `droppartion_del`()
    SQL SECURITY INVOKER
label1:BEGIN
declare _droppart int;
declare _i int;
DECLARE _dbname varchar(40);
declare _droppartlist varchar(500);
set _dbname=database();
        if (select count(*) from information_schema.PROCESSLIST where db =_dbname) >1 then
             select -1,'some process on db, please check it !';
            LEAVE label1;
        end if ;
    if   substring_index(_dbname,'_',1)='del'  then         
        drop table if exists tablename_tmp;
        create table tablename_tmp(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,table_name varchar(40),primary key (id));
        insert into tablename_tmp(table_name) select table_name from information_schema.PARTITIONS where table_schema =_dbname and partition_name is not null group by  table_name HAVING count(*) >3;
        select count(*) into @tablenum from tablename_tmp;
        set _i=1;  
        while _i <=@tablenum  do 
            select substring(partition_name,2) into _droppart  from information_schema.PARTITIONS  where table_schema = _dbname and table_name =(select table_name from tablename_tmp where id=_i ) order by partition_name  desc limit 2,1;
            select group_concat(partition_name) into _droppartlist from information_schema.PARTITIONS where table_schema =_dbname and table_name=(select table_name from tablename_tmp where id=_i ) and substring(partition_name,2) <_droppart  group by table_schema,table_name;
            SET @stmt = CONCAT('alter table ' ,(select table_name from tablename_tmp where id=_i),' drop partition ' ,_droppartlist,' ;');
            prepare SQL1 FROM @stmt;
            EXECUTE  SQL1;        
            set _i=_i+1;
        end while;
        
        truncate table tablename_tmp;
        insert into tablename_tmp(table_name) select table_name from information_schema.TABLES where table_schema =_dbname and table_name<>'tablename_tmp';
        select count(*) into @tablenum from tablename_tmp;
        
        set _i=1;  
        while _i <=@tablenum  do 
            SET @stmt = CONCAT('drop table if exists ' ,(select table_name from tablename_tmp where id=_i),' ;');
            prepare SQL1 FROM @stmt;
            EXECUTE  SQL1;        
            set _i=_i+1;
        end while;
        
        select 1,'succeed!!';
    else 
        select -2,'we can only drop database which name like  del_XXX,please check it!';
        LEAVE label1;
    end if;
        
END$$

DELIMITER ;

 

 

二、DBA認為某些庫需要刪除:

        這種情況,一般是空間不足,然后有dba 認為不需要使用的庫,可以清理的時候。

       流程基本和上面一種情況差不多,只是要dba主動找開發,業務確認,並且做好個方便的准備來確認庫是否還有業務訪問。

三、業務邏輯需要按規則刪除庫:

  對於這個需求,主要是游戲業務,合區過后清除數據的時候使用,這種相對來說判斷就要簡單一些,只是不確定每個表的大小,表的數量,建議在做整合腳本的時候,盡量化整為零,多次刪除。

 

 

總結,以上情況都是基於線上環境考慮的, 如果僅僅是開發測試環境,個人覺得沒有相對沒那么麻煩,

做了基本確認, 然后做rename database, 備份,一段時間drop 掉 數據庫就好了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM