如何在 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');