【问题标题】:Delete the remaining rows MySql删除剩余的行MySql
【发布时间】:2021-08-30 08:21:28
【问题描述】:
  1. 假设有一个包含 1M 行的表,其类别为 1-100。
  2. 我需要更新 f.e. category=10(假设有 150k 行)。
  3. 我将更新 120k 行,需要删除 30k 行。

第一个想法: 目前我正在使用开始将所有行更新为 0,并在更新时将此值更改为 1。然后删除 category=10 和 update=0 的所有行。

在 category=10 的情况下,将 150k 行更新为 0 时存在性能问题。有时需要 30 秒,因为可能有 200k 行,而不仅仅是 30k。

第二个想法 一开始,循环所有 150k 行以将 id 保留在数组中,然后用更新的 id 填充一个新数组,最后使用 array_diff 删除剩余的 id。

使 sql 类似于“... where id in (...30k ids...)”的性能也存在问题。

你们使用更好的方法来解决这项工作吗? 谢谢。

【问题讨论】:

  • 不明白,如果您能够更新符合条件的行( WHERE ...)您应该能够使用否定的 crtiria 删除(WHER NOT (...) )
  • @Dri372 不。想象一下,有 100 万个产品的提要。那些不再在提要中的应该被删除。我不知道他们是谁,有多少人。我正在循环交叉提要并更新提要中的产品。其他所有内容都需要从 db 中删除。
  • @Dri372 我可以使用“WHERE NOT IN (...)”之类的查询,但 ID 约为 150k?需要为这个问题制定一些最聪明的解决方案。

标签: mysql loops updates


【解决方案1】:

您的第一个想法的变化:将您的标志列定义为时间戳而不是布尔值,然后您不必花 30 秒将其初始化为 0。只需将该时间戳更新为 NOW () 更新行时。完成后,应删除标志列早于您的第一个更新行的任何行。我假设此更新/删除任务将定期再次完成,但只要任务不重叠,时间戳应该仍然有效。

第二个想法的变体:不要运行查询DELETE FROM imagine WHERE id IN(...30k ids...) 谓词。相反,您可以运行一系列DELETE FROM imagine WHERE id IN (...100 ids...)。循环遍历您的 id 列表并一次删除 100 个。您需要以这种方式运行 300 条 DELETE 语句,但编写循环很容易。

【讨论】:

  • 两种解决方案都是不错的选择!谢谢你。在第一个解决方案。为什么在 php 中不仅使用 INT 和像 time() 这样的更新,然后删除比第一个更新行更早的所有内容? mysql 中的结构时间戳类似于“2021-06-14 20:28:06”。是否可以删除
  • 好的,在谷歌搜索之后,现在我知道可以删除所有早于“2021-06-14 20:28:06”的行。我想,这是某种需要转换为“1623696480”的格式。非常感谢您的帮助!
  • 只有最后一个补充问题。删除早于“2021-06-14 20:28:06”的所有行是否比删除 something=0 的所有行更快?
  • 无论哪种方式,行数都是相同的。这可能会对性能产生更大的影响。
  • 在测试从 200k 表中删除 200k 行后,两个查询(delete where something=0 or something~0,7s 。可能没有区别,但是如果您的初始更新行的想法像以前一样节省更多时间,这并不重要。
【解决方案2】:

解决方案 1bis,如果您正在寻找性能

动态添加默认值为 0 的新字段比为现有字段更新 30K 行要快。

最后你可以删除这个字段,这也是一个快速命令。

【讨论】:

  • 它们默认为 0。在更新中它们是 1,然后在下一次更新中它们仍然是 1,所以我需要将它改回 0,这需要一些时间来将 30k 或 200k 行更新为 0正如我在上面写的那样。
  • 它看到你不明白我的答案,当然更新需要时间,但我写的是动态创建字段,不需要更新为 0。它比 upate 快得多,可能与时间戳一起工作。我通过添加动态来更新答案,但是当我通过删除字段结束它时应该很清楚。
  • 好的,现在我明白了。这可能是解决方案,但我认为这是必要的又一个不必要的步骤。无论如何,感谢您对这个问题提出新的看法。
  • 感谢您的评论,如果您进行测试,请告诉我们与使用时间戳的对比 ....
  • 创建一个默认值为 0 的新列需要“无”。但是最终删除它需要太多时间。我需要实际操作大约 30k 行并添加/删除 1M 行的列。好主意,但不适用于大桌子。 1M 只是一个例子。将有超过 10M 行。
【解决方案3】:

大更新(或删除)代价高昂,因为在发生崩溃时需要保存旧行。

如果这是一项一次性任务并且您无需担心在更新期间会阻塞其他活动,那么只需执行查询,并在必要时让它们花几分钟时间。

如果您有其他限制,请说明。请提供SHOW CREATE TABLE,以及建议的更新和删除语句。

在某些情况下,最好使用PRIMARY KEY 遍历表格。一次做 1000 行。也就是说,首先找到跨越该范围的 id 范围,然后执行每个更新和删除,但限制(通过WHERE)到该范围。 (在某些情况下,他们可能不会修改任何行,但这没关系。)COMMIT 在每个块之后。

更多详情:http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks

【讨论】:

  • 嗨@rick-james 有/你可以阅读我的上一条评论comcompating mysql et postgresl。这是非常近似的,但可以更深入地了解......你应该可以进行一些交叉测试吗?
猜你喜欢
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多