【问题标题】:Replace Into Query Syntax替换成查询语法
【发布时间】:2013-11-18 04:48:20
【问题描述】:

我希望能够使用“replace into”语句更新具有相同架构的表。最后,我需要能够使用可能已更改的值更新一个大表。

这是我用来开始的查询:

REPLACE INTO table_name
(visual, inspection_status, inspector_name, gelpak_name, gelpak_location),
VALUES (3, 'Partially Inspected', 'Me', 'GP1234', 'A01');

我不明白的是数据库引擎如何知道什么是重复行,什么不是?这些数据非常重要,我不能冒数据被损坏的风险。是否像“如果列出的所有列都具有相同的值,则它是重复行”那么简单?

我只是想找出一种有效的方法来做到这一点,这样我就可以在一分钟内更新超过 45,000 行。

【问题讨论】:

  • 您是否找到了一种在一分钟内无错误地更新和更多记录的方法?此查询是否正常运行?
  • 我知道这个问题很长,但要记住,正如其他人在下面指出的那样,REPLACE 会执行 INSERT,但如果记录已经存在,它会执行 DELETE 然后 INSERT。人们不考虑的一个后果是,如果目标表是任何 PK/FK 关系中的 PK 表,那么对于有其他依赖于它们的记录的 DELETE 将失败(默认行为),或者如果关系具有 CASCADE DELETE 然后子表中的记录将被删除,之后不会再回来。

标签: mysql sql database replace


【解决方案1】:

正如documentation 所说:

REPLACE 的工作方式与 INSERT 完全相同,只是如果表中的旧行与 PRIMARY KEY 或 UNIQUE 索引的新行具有相同的值,则在插入新行之前删除旧行。

【讨论】:

  • 请注意,“删除然后插入”可能非常慢 - 比 SELECT 后跟 UPDATE 或 INSERT 慢得多(无论哪个合适)。 DELETE 使索引无效。 INSERT ... ON DUPLICATE UPDATE... 比 REPLACE 稍微快一点,但仍然比 SELECT+UPDATE 慢得多。无论如何,对我来说 - 衡量你的表现。
【解决方案2】:

REPLACE 的工作原理很像 INSERT,它只是覆盖具有相同 PRIMARY KEYUNIQUE 索引的记录,但是请注意。

Shlomi Noach 写了关于使用 REPLACE INTO here 的问题:

但是像我这样心软的人应该注意以下几点:这是一个重量级的解决方案。就易用性而言,这可能正是您所寻找的,但事实是,在重复键上,会执行 DELETE 和 INSERT,这需要仔细研究。

每当删除一行时,所有索引都需要更新,最重要的是 PRIMARY KEY。当插入新行时,也会发生同样的情况。特别是在 InnoDB 表上(因为它们的集群性质),这意味着很多开销。指数的重组是一项昂贵的操作。索引节点可能需要在 DELETE 时合并。由于 INSERT 可能需要拆分节点。在多次执行 REPLACE INTO 之后,如果您使用 SELECT/UPDATE 或 INSERT INTO ... ON DUPLICATE KEY,那么您的索引很可能会比原来更加碎片化

此外,还有“好吧,如果行不存在,我们创建它。如果存在,它只是得到更新”的概念。这是错误的。该行不仅被更新,而且被完全删除。问题是,如果该表上有一个 PRIMARY KEY,并且 REPLACE INTO 没有为 PRIMARY KEY 指定一个值(例如,它是一个 AUTO_INCREMENT 列),那么新行会得到一个不同的值,这可能不是什么你在寻找行为方面。

REPLACE INTO 的许多用法无意更改 PRIMARY KEY(或其他 UNIQUE KEY)值。在这种情况下,最好不要管它。在我见过的生产系统上,将 REPLACE INTO 更改为 INSERT INTO ... ON DPLICATE KEY 会导致吞吐量增加十倍(以每秒查询数衡量),并大幅减少 IO 操作和平均负载。

总之,REPLACE INTO可能适合您的实施,但您可能会发现改用INSERT ... ON DUPLICATE KEY UPDATE 更合适(风险也更小)。

【讨论】:

    【解决方案3】:

    或类似的东西:

    insert ignore tbl1 (select * from tbl2);
    
    UPDATE
            `tbl1` AS `dest`,
            (SELECT * FROM tbl2) AS `src`
        SET
           dest.field=src.field,
           dest.field=if (length(src.field)>0,src.field,dest.field) /* or anything like that*/
        WHERE
            `dest`.id = `src`.id; 
    

    【讨论】:

      猜你喜欢
      • 2019-05-22
      • 2021-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      • 2018-06-08
      • 2012-06-18
      相关资源
      最近更新 更多