【问题标题】:MySQL efficiently copy all records from one table to anotherMySQL 有效地将所有记录从一个表复制到另一个表
【发布时间】:2012-06-26 15:43:06
【问题描述】:

有没有一种更有效、更省力的方法将所有记录从一个表复制到另一个表:

INSERT INTO product_backup SELECT * FROM product

通常,product 表将保存大约 50,000 条记录。两个表的结构相同,有 31 列。我想指出这不是我的数据库设计,我继承了旧系统。

【问题讨论】:

  • 我认为这是最好的方法。通过这种方式,您也可以保留索引。
  • Speedwise 已经达到了最好的水平。当然,您可以将备份表上的索引创建推迟到所有数据都复制完之后,这将显着提高插入速度。
  • 这很有趣,谢谢。我对数据的复制感到好奇,想知道这是否会消耗数据库(SELECT * 让我失望,或者由于查询的构造方式需要很长时间来处理)。如果这是一种可以接受的复制数据的方式,那很好。
  • 我认为如果您有数百万行,您可能会遇到麻烦。在这种情况下,您可以使用转储/加载解决方案。
  • 我永远不会在这个表中有数百万行。我看不到有 > 100,000

标签: mysql sql insert mysql5


【解决方案1】:

您只缺少一件事。特别是,如果您使用 InnoDB,是否要在 SELECT 语句中显式添加 ORDER BY 子句,以确保以主键(聚集索引)顺序插入行:

INSERT INTO product_backup SELECT * FROM product ORDER BY product_id

如果不需要,请考虑删除备份表上的二级索引。这也将节省服务器上的一些负载。

最后,如果您使用 InnoDB,请减少所需的行锁数量,并显式锁定两个表:

LOCK TABLES product_backup WRITE;
LOCK TABLES product READ;
INSERT INTO product_backup SELECT * FROM product ORDER BY product_id;
UNLOCK TABLES;

锁定的东西可能不会有很大的不同,因为行锁定非常快(虽然不如表锁快),但正如你所问的那样。

【讨论】:

  • 我正在使用 MyISAM 引擎。我在之前的一篇文章中提到我继承了一个遗留系统,所以目前是 MyISAM。
  • 无法排序创建不平衡的索引树?在哪种情况下,随机顺序可能更适合主键?
  • @DannyStaple,当使用 MyISAM 按排序顺序插入索引时,树是扁平的。这提高了性能(不必重建索引),并节省了空间。来自MySQL documentation:“当按排序顺序插入行时(如使用 AUTO_INCREMENT 列时),索引树将被拆分,以便高节点仅包含一个键。这提高了索引树中的空间利用率。”
  • 第二个代码块的第二行应该是LOCK TABLES product;product_id是列。
【解决方案2】:
mysqldump -R --add-drop-table db_name table_name > filepath/file_name.sql

这将使用删除选项转储指定的表,以便在您导入现有表时将其删除。然后做,

mysql db_name < filepath/file_name.sql

【讨论】:

  • 我应该补充说我是在 PHP 代码中执行此操作的。它将在product 表上执行一系列 INSERT 和 UPDATE 之前完成,因此我希望在 PHP 代码而不是 MySQL 管理函数中执行此操作。
【解决方案3】:

DROP目标表:

DROP TABLE DESTINATION_TABLE;
CREATE TABLE DESTINATION_TABLE AS (SELECT * FROM SOURCE_TABLE);

【讨论】:

  • 如果目标表中已经存在 OP 想要保留和添加的数据怎么办?
  • 为什么要删除并创建表而不是 DELETE FROM destination_table; INSERT INTO destination_table SELECT * FROM 产品?哪个效率更高?
  • Drop 将重置主自动增量 ID
  • 将这个用于 Django 管理的 DB 破坏了表格。即使正确设置了主键和自动增量指令,新行也被添加了相同的主键! (不增加)。但奇怪的是,一旦添加这些行,我就无法删除它们,因为它会引发“收到意外更新计数”错误。我必须删除并恢复我的架构才能解决此问题。
【解决方案4】:

我认为这对于 50k 的桌子来说不值得,但是: 如果您有数据库转储,则可以从中重新加载表。当您想在另一个表中加载表时,您可以使用 sed 命令更改转储中的表名: 这里有一些提示: http://blog.tsheets.com/2008/tips-tricks/mysql-restoring-a-single-table-from-a-huge-mysqldump-file.html

另一种选择(取决于您的设计)是在原始表插入上使用触发器,以便重复的表也能获取数据。

更好的选择是创建另一个 MySQL 实例,然后以主从配置或每日转储主/负载从属方式运行它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 2012-08-12
    • 1970-01-01
    • 2015-05-05
    相关资源
    最近更新 更多