如何在 mysql 数据库中复制模式
How to duplicate a schema in mysql database
目标
在 mysql 数据库中复制模式,不转储 sql 文件并执行它们。
如果有一种方法可以通过几个命令来完成此任务,那就太好了。
背景
有一些方法可以转储数据库并通过执行转储程序生成的 sql 来导入它。
但我想做的是执行像 copy schema abc to abc_bk
这样的命令,然后完成。
因为我必须通过 phpmyadmin 来完成,并且转储所有字段并重新导入它们太耗时了。
有说法:
CREATE TABLE <name> LIKE <othername>;
但是你必须一次做一个 table。没有一个语句可以对架构中的所有 table 执行此操作。
您可以从 INFORMATION_SCHEMA.TABLES 获得 table 的列表:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = <old-schema>;
然后对于该查询返回的每个 table,运行 语句:
CREATE TABLE <new-schema>.<table-name> LIKE <old-schema>.<table-name>;
您必须编写一些代码来执行循环才能执行此操作。
回复您的评论:
如果你也想复制数据,可以使用INSERT ... SELECT。
INSERT INTO <new-schema>.<table-name>
SELECT * FROM <old-schema>.<table-name>;
这需要一段时间,与它需要在你的 table 中更新的行数和索引数成正比(即,写入每行的成本乘以索引数) .
请注意,当 INSERT...SELECT 为 运行ning 时,这会锁定它从旧 table 读取的行。如果您需要继续写入旧的 table,我建议您使用 pt-archiver or pt-table-sync 进行复制。
就我而言,我想基于现有数据库创建一个全新的数据库,用于我的集成测试。它基本上是 Bill Karwin 上述回答的充实版本。
请注意,我的解决方案不会复制数据。如果您需要该功能,添加到脚本中应该不会太困难。
你可以参考GitHub Gist here.
这是供快速参考的 MySQL 代码:
-- this procedure needs to be run somewhere, so just select a database
USE `existing_db`;
DELIMITER $$
DROP PROCEDURE IF EXISTS `exec`$$
DROP PROCEDURE IF EXISTS `copy_schema`$$
-- simple procedure to allow statement strings to be built and executed easily
-- using `concat`
CREATE PROCEDURE exec(stmt_text TEXT)
BEGIN
SET @sql_text = stmt_text;
PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
-- Copies the database `from_db` into a new database, `to_db`.
-- Be careful: This procedure DROPs `to_db` before copying data
CREATE PROCEDURE copy_schema(from_db VARCHAR(64), to_db VARCHAR(64))
BEGIN
-- declare variables to be used throughout the procedure
DECLARE curr_table_name VARCHAR(64) DEFAULT NULL;
DECLARE done TINYINT DEFAULT FALSE;
-- This is a cursor that will point to every row in
-- INFORMATION_SCHEMA.TABLES
-- Each row corresponds to a table in `from_db`, so this will effectively
-- give us a foreach loop through the table names
DECLARE table_cursor
CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = from_db;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- initialize `to_db` before attempting to copy data into it
CALL exec(concat('DROP DATABASE IF EXISTS ', to_db));
CALL exec(concat('CREATE DATABASE ', to_db));
OPEN table_cursor;
-- Loop through all table names
table_loop:
LOOP
FETCH NEXT FROM table_cursor INTO curr_table_name;
-- Break if no more results
IF done THEN
LEAVE table_loop;
ELSE
-- Call `CREATE TABLE` for each table, copying the schema from `from_db`
CALL exec(concat('CREATE TABLE ', to_db, '.', curr_table_name, ' LIKE ', from_db, '.', curr_table_name));
END IF;
END LOOP;
CLOSE table_cursor;
END $$
DELIMITER ;
-- EXAMPLE USAGE:
CALL copy_schema('existing_db', 'existing_db_copy');
目标
在 mysql 数据库中复制模式,不转储 sql 文件并执行它们。
如果有一种方法可以通过几个命令来完成此任务,那就太好了。
背景
有一些方法可以转储数据库并通过执行转储程序生成的 sql 来导入它。
但我想做的是执行像 copy schema abc to abc_bk
这样的命令,然后完成。
因为我必须通过 phpmyadmin 来完成,并且转储所有字段并重新导入它们太耗时了。
有说法:
CREATE TABLE <name> LIKE <othername>;
但是你必须一次做一个 table。没有一个语句可以对架构中的所有 table 执行此操作。
您可以从 INFORMATION_SCHEMA.TABLES 获得 table 的列表:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = <old-schema>;
然后对于该查询返回的每个 table,运行 语句:
CREATE TABLE <new-schema>.<table-name> LIKE <old-schema>.<table-name>;
您必须编写一些代码来执行循环才能执行此操作。
回复您的评论:
如果你也想复制数据,可以使用INSERT ... SELECT。
INSERT INTO <new-schema>.<table-name>
SELECT * FROM <old-schema>.<table-name>;
这需要一段时间,与它需要在你的 table 中更新的行数和索引数成正比(即,写入每行的成本乘以索引数) .
请注意,当 INSERT...SELECT 为 运行ning 时,这会锁定它从旧 table 读取的行。如果您需要继续写入旧的 table,我建议您使用 pt-archiver or pt-table-sync 进行复制。
就我而言,我想基于现有数据库创建一个全新的数据库,用于我的集成测试。它基本上是 Bill Karwin 上述回答的充实版本。
请注意,我的解决方案不会复制数据。如果您需要该功能,添加到脚本中应该不会太困难。
你可以参考GitHub Gist here.
这是供快速参考的 MySQL 代码:
-- this procedure needs to be run somewhere, so just select a database
USE `existing_db`;
DELIMITER $$
DROP PROCEDURE IF EXISTS `exec`$$
DROP PROCEDURE IF EXISTS `copy_schema`$$
-- simple procedure to allow statement strings to be built and executed easily
-- using `concat`
CREATE PROCEDURE exec(stmt_text TEXT)
BEGIN
SET @sql_text = stmt_text;
PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
-- Copies the database `from_db` into a new database, `to_db`.
-- Be careful: This procedure DROPs `to_db` before copying data
CREATE PROCEDURE copy_schema(from_db VARCHAR(64), to_db VARCHAR(64))
BEGIN
-- declare variables to be used throughout the procedure
DECLARE curr_table_name VARCHAR(64) DEFAULT NULL;
DECLARE done TINYINT DEFAULT FALSE;
-- This is a cursor that will point to every row in
-- INFORMATION_SCHEMA.TABLES
-- Each row corresponds to a table in `from_db`, so this will effectively
-- give us a foreach loop through the table names
DECLARE table_cursor
CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = from_db;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- initialize `to_db` before attempting to copy data into it
CALL exec(concat('DROP DATABASE IF EXISTS ', to_db));
CALL exec(concat('CREATE DATABASE ', to_db));
OPEN table_cursor;
-- Loop through all table names
table_loop:
LOOP
FETCH NEXT FROM table_cursor INTO curr_table_name;
-- Break if no more results
IF done THEN
LEAVE table_loop;
ELSE
-- Call `CREATE TABLE` for each table, copying the schema from `from_db`
CALL exec(concat('CREATE TABLE ', to_db, '.', curr_table_name, ' LIKE ', from_db, '.', curr_table_name));
END IF;
END LOOP;
CLOSE table_cursor;
END $$
DELIMITER ;
-- EXAMPLE USAGE:
CALL copy_schema('existing_db', 'existing_db_copy');