foreplay

Sometimes the production environment is named after the project, and sometimes there will be a name change. In fact, how to change the database name safely is a very difficult problem, especially for MySQL databases.

canceled order

MySQL previously provided a rename database db_old to db_new command to directly rename the database, which may be due to incomplete functions (for example, this command may be a very large transaction, or because there are many previous tables or MyISAM, etc.), Later versions directly canceled this command.

There are roughly the following options for changing the database name:

mysqldump import and export

The easiest way is to directly use the mysqldump tool to export from the old library and then import it into the new library (the most original, slowest, and easiest to think of) method:

旧库 yttdb_old 导出(包含的对象:表、视图、触发器、事件、存储过程、存储函数)
time mysqldump --login-path=root_ytt --set-gtidpurged=off --single-transaction --routines --events yttdb_old >
/tmp/yttdb_old.sql
real 2m24.388s
user 0m5.422s
sys 0m1.120s
新库 yttdb_new 导入
time mysql --login-path=root_ytt -D yttdb_new <
/tmp/yttdb_old.sql
real 12m27.324s
user 0m3.778s
sys 0m0.947s

Change the table name of the library

Use MySQL to change the table name to traverse all the tables in the old database in batches and rename them to the tables in the new database.

This method is many times faster than the first method, but it is not as smooth as the first step, and cannot be completed in one step. For example, to rename the database yttdb_old to yttdb_new, if there are only disk tables in the database yttdb_old, it is very simple, just change the name directly

alter table yttdb_old.t1 to yttdb_new.t1;

Or write a script to batch change, very simple. But in general, there are not only disk tables in the old library, but also various other objects. At this time, you can first consider exporting various objects of the old library, and then import them after changing the table names one by one.

Export all objects (stored functions, stored procedures, triggers, events) under the old library yttdb_old except disk tables

time mysqldump --login-path=root_ytt -t -d -n --setgtid-purged=off --triggers --routines --events yttdb_old > 
/tmp/yttdb_old_other_object.sql
real 1m41.901s
user 0m1.166s
sys 0m0.606s

Views are regarded as tables in MySQL, so you have to find out the name of the view first, and then export it separately:

view_list=`mysql --login-path=root_ytt -e "SELECT table_name FROM information_schema.views WHERE table_schema='yttdb_old';" -s | tr '\n' ' '`
time mysqldump --login-path=root_ytt --set-gtid-purged=off -- triggers=false yttdb_old $view_list > /tmp/yttdb_old_view_lists.sql
real 0m0.123s
user 0m0.007s
sys 0m0.007s

After these extra objects are successfully exported, they can be deleted in the old library. Of course, before doing these operations, it is recommended to put the old library

All objects, including tables, are backed up. There are many backup methods, so I won’t go into details here. Now let's delete these objects in turn: (Actually, except for triggers and views, other objects do not need to be deleted, but in order to clear the old library after renaming, they must be deleted first).

For the sake of clarity, I delete each object individually, or delete them all at once.

Batch delete stored functions

func_lists=`mysql --login-path=root_ytt -e "SELECT concat('drop function if exists ',routine_name,';') FROM 
information_schema.routines WHERE routine_schema = 'yttdb_old' AND routine_type = 1 " -ss

time mysql --login-path=root_ytt -e "use yttdb_old;$func_lists"
real 0m0.048s
user 0m0.005s
sys 0m0.005s

Batch delete stored procedure:

procedure_lists=`mysql --login-path=root_ytt -e "SELECT concat('drop procedure if exists ',routine_name,';') FROM information_schema.routines WHERE routine_schema = 'yttdb_old' AND routine_type = 2 " -ss`
time mysql --login-path=root_ytt -e "use yttdb_old;$procedure_lists"
real 0m0.046s
user 0m0.006s
sys 0m0.005s

Bulk delete triggers:

trigger_lists=`mysql --login-path=root_ytt -e "SELECT concat('drop trigger if exists yttdb_old.',trigger_name,';') FROM information_schema.TRIGGERS WHERE trigger_schema='yttdb_old'" -ss`
time mysql --login-path=root_ytt -e "use yttdb_old;$trigger_lists"
real 0m0.050s
user 0m0.008s
sys 0m0.003s

Bulk delete views:

view_lists=`mysql --login-path=root_ytt -e "SELECT concat('drop view if exists ',table_name,';') FROM information_schema.VIEWS WHERE table_schema='yttdb_old'" -ss`
time mysql --login-path=root_ytt -e "use yttdb_old;$view_lists"
real 0m0.070s
user 0m0.006s
sys 0m0.005s

Batch delete events:

 event_lists=`mysql --login-path=root_ytt -e "SELECT concat('drop event if exists ',event_name,';') FROM information_schema.EVENTS WHERE event_schema='yttdb_old'" -ss`
time mysql --login-path=root_ytt -e "use yttdb_old;$event_lists"
real 0m0.054s
user 0m0.011s
sys 0m0.000s
完了后利用 rename table old_table to new_table 语句来批量更改表名到新库:
(debian-ytt1:3500)|(yttdb_new)>set group_concat_max_len = 18446744073709551615;
Query OK, 0 rows affected (0.00 sec)
(debian-ytt1:3500)|(yttdb_new)>SELECT CONCAT('rename table ',
GROUP_CONCAT(CONCAT(' yttdb_old.',table_name,' to
yttdb_new.',table_name)) )
FROM information_schema.TABLES
WHERE table_schema = 'yttdb_old' AND table_type = 1 INTO @rename_lists;
Query OK, 1 row affected (0.01 sec)
(debian-ytt1:3500)|(yttdb_new)>prepare s1 from @rename_lists;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
(debian-ytt1:3500)|(yttdb_new)>execute s1;
Query OK, 0 rows affected (55.41 sec)
(debian-ytt1:3500)|(yttdb_new)>drop prepare s1;
Query OK, 0 rows affected (00.01 sec)

批量更改表名总共才花费 55.41 秒。接下来再把之前导出的其他对象导入新库 yttdb_new:

time mysql --login-path=root_ytt -D yttdb_new < 
/tmp/yttdb_old_other_object.sql
real 0m0.222s
user 0m0.081s
sys 0m0.000s
time mysql --login-path=root_ytt -D yttdb_new <
/tmp/yttdb_old_view_lists.sql
real 0m0.158s
user 0m0.013s
sys 0m0.000s

接下来进行功能验证,验证表数量、触发器、存储过程、存储函数、事件等数目是不是对的上。

古老的方案

其实在 MySQL 早期还有一种方法。

假设 MySQL 部署好了后,所有的 binlog 都有备份,并且二进制日志格式还是 statement 的话,那就可 以简单搭建一台从机,让它慢慢追主机到新的库名,等确切要更改旧库的时候,再直接晋升从机为主机即 可。 这里只需要从机配置一个参数来把旧库指向为新库: replicate-rewrite-db=yttdb_old->yttdb_new 不过这种局限性很大,不具备标准化,不推荐。

总结

其实针对 MySQL 本身改库名,大致就这么几种方法:

  1. 如果数据量小,推荐第一种;
  2. 数据量大,则推荐第二种;
  3. 数据量巨大,那就非 MySQL 本身能解决的了。

可通过部署第三方 ETL 工具,通过解析 MySQL 二进制日志或其他的方式来把旧库数据直接读取到新库达到改名的目的等等

MySQL数据库如何改名_sql