【问题标题】:Mysql fastest technique for insert, replace, on duplicate of mass recordsMysql最快的插入、替换、复制大量记录的技术
【发布时间】:2022-12-18 14:21:19
【问题描述】:

我知道有很多相关问题和很多答案,但我有一个更微妙的问题。我一直在阅读有关大量记录的不同插入技术,但是查询插入的大小有限制吗?可以将相同的技术用于 REPLACEINSERT ...ON DUPLICATE KEY UPDATE ... 吗?有没有更快的方法?

桌子:

+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| a         | int(11)     | NO   | PRI | NULL    | auto_increment |
| b         | int(11)     | YES  |     | NULL    |                |
| c         | int(11)     | YES  |     | NULL    |                |

#1

1) "INSERT INTO TABLE COLUMNS (a,b,c) values (1,2,3);"
2) "INSERT INTO TABLE COLUMNS (a,b,c) values (5,6,7);"
3) "INSERT INTO TABLE COLUMNS (a,b,c) values (8,9,10);"
 ...
10,000) "INSERT INTO TABLE COLUMNS (a,b,c) values (30001,30002,30003);"

或者

#2 - 应该更快,但有限制吗?

"INSERT INTO TABLE COLUMNS (a,b,c) values (1,2,3),(4,5,6),(8,9,10)....(30001,30002,30003)" ;

从脚本的角度 (PHP) 来看,使用 #2,是循环遍历 100 个条目(1000 次)并将其排队更好……还是 1000 个条目(100 次),或者一次全部 10,000 个?这可以用 100,000 个条目完成吗?

同样可以与REPLACE一起使用吗:

"REPLACE INTO TABLE (a, b, c) VALUES(1,2,3),(4,5,6)(7,8,9),...(30001,30002,30003);"

它也可以与INSERT ON DUPLICATE一起使用吗?

INSERT INTO TABLE (a, b, c) VALUES(1,2,3),(4,5,6),(7,8,9),....(30001,30002,30003) ON DUPLICATE KEY UPDATE (b=2,c=3)(b=5,c=6),(b=8,c=9),....(b=30002,c=30003) ?

对于以上所有内容(假设替换/重复有效),是否有更快的方法来实现插入?

【问题讨论】:

  • 你真的有哪种情况?全新行的简单插入?或者您可能需要替换/更新现有行?

标签: mysql insert sql-insert upsert


【解决方案1】:

任何 SQL 语句的长度都受到名为 max_allowed_packet 的 MySQL 选项的限制。

INSERT 的语法允许在 VALUES 子句后添加无限数量的元组,但是语句从INSERT到最后一个元组的总长度仍然不能超过等于max_allowed_packet的字节数。

不管怎样,我发现 LOAD DATA INFILE 通常比任何 INSERT 语法都快得多。它快得多,您甚至可能会发现将元组写入临时 CSV 文件然后在该 CSV 文件上使用 LOAD DATA INFILE 会更快。

您可能喜欢我的演示文稿,它比较了 MySQL 中不同的批量加载解决方案:Load Data Fast!

【讨论】:

  • 我的表单提供了三个用于上传 CSV 文件的选项。 1.上传新的或删除现有的并上传新的。 2. 上传新的并合并而不更新重复项 3) 上传新的并合并和更新重复项。这个任务是让我走上这条路的原因所以对于#1,我直接从文件加载。但是对于#2 和#3,我需要进行比较以检查if not exist then insert,最后检查if not exist insert, but if exists then update。因此我的问题与REPLACEON DUPLICATE 有关
  • Bill,甚至是 documented:“从文本文件加载表时,使用 LOAD DATA。这通常比使用 INSERT 语句快 20 倍。”
  • @rolinger,我鼓励你看看documentation for LOAD DATA。它有一个可选的关键字 REPLACE 可以做你想做的事。
  • @BillKarwin - 谢谢。我想我的三个需求都可以用这个来满足。 #1 = 删除所有记录然后LOAD DATA LOCAL INFILE $file ....,#2 = 仅合并新记录:LOAD DATA LOCAL INFILE $file IGNORE... 和#3 = 合并新记录并更新现有记录:LOAD DATA LOCAL INFILE $file REPLACE...
【解决方案2】:

#1(单行插入)——慢。一个变体是INSERT IGNORE——注意:它会烧掉AUTO_INCREMENTid。

#2(批量插入)——比#1 快 10 倍。但是批量插入不超过 1000 个。(之后,您将进入“收益递减”状态,并且可能与其他活动发生冲突。

#3 REPLACE——不好。它本质上是一个DELETE加上一个INSERT。将 IODKU 添加到 MySQL 后,我认为 REPLACE 没有任何用处。所有旧的AUTO_INCREMENT id 都将被丢弃并创建新的。

#4 IODKU (Upsert) -- [如果你需要在 Insert 之前测试。]它能够进行批处理,但不是您呈现的方式。 (无需重复 bc 值。)

INSERT INTO (
INSERT INTO TABLE (a, b, c)
     VALUES(1,2,3),(4,5,6),(7,8,9),....(30001,30002,30003)
     ON DUPLICATE KEY UPDATE
         b = VALUES(b),
         c = VALUES(c);

或者,在 MySQL 8.0 中,最后两行是:

         b = NEW.b,
         c = NEW.c;

IODKU 也会烧掉 id。

MySQL LOAD DATA INFILE with ON DUPLICATE KEY UPDATE 讨论了LOAD + IODKU 的两步过程。根据“更新”的复杂程度,2 个以上的步骤可能是您的最佳答案。

#5 LOAD DATA——正如比尔所说,这是个好方法如果数据来自文件。 (我怀疑它的速度,如果你也必须首先将数据写入文件。)请注意@variables 在加载时进行细微调整的用处。 (例如,STR_TO_DATE(..) 以修复 DATE 格式。)

#6 INSERT ... SELECT ...; -- 如果数据已经在其他一些表中,您也可以结合插入和选择。这也适用于 IODKU。

作为旁注,如果您需要获取每个批处理行的 AUTO_INCREMENT id,我推荐以下一些变体。它旨在对可能已经存在于映射表中的 id-name 对进行批量规范化。 Normalization

【讨论】:

  • 感谢您的详细解释。这有帮助。我的原始帖子源于试图找出导入 csv 文件的最佳方法 - 处理速度、重复、更新和新插入。因此@BillKarwan 的回答让我走上了正确的道路,我重写了所有内容以现在使用LOAD DATA LOCAL INFILE。但我现在使用REPLACE 进行更新,使用IGNORE 进行重复。根据您所写的内容,我如何将 IODKU 与 LOAD DATA 一起使用?它似乎不支持ON DUPLICATE
  • 我发现这是一种解决方法,现在有更好的技术吗? - 这篇文章很老了。 stackoverflow.com/questions/15271202/…
  • @rolinger-谢谢;我将指向该 Q+A 的链接折叠到我的答案中。是的,我同意。 -- LOAD 非常快; IODKU 非常强大。在它们之间(可能还有其他一些步骤——但没有循环——你应该有一个快速的处理更新的强大方法。
  • 我使用临时表方法完成所有这些工作,然后执行 IODKU insert in to mainTable SELECT * FROM tempTable - 但我有一个问题。在 mainTable 中我有三个索引:primary key=uid, unique key (listID,phone), unique key (listID,email)mainTable中的每个列表只能有一个邮箱或电话号码,不能重复。 ON DUPLICATE KEY 是否强制主键和唯一键都唯一......或者它只适用于主键或第一个匹配项(以确定重复项)。在我的设置中,我什至不关心主键。
  • @rolinger - 是的,所以要小心。 3 个唯一键中的任何一个或全部都将触发 IODKU 的“更新”端。请提供SHOW CREATE TABLE进一步讨论。 (如果 PK 是未在任何 JOIN 中使用的 auto_increment,也许您应该摆脱它,并将其中一个 UNIQUE 提升为 PK。)
猜你喜欢
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 2015-03-31
  • 2020-07-01
  • 2011-02-15
  • 2012-05-23
  • 1970-01-01
相关资源
最近更新 更多