- 假设有一个表,其中有1M行,类别为1-100
- 我需要更新f.e.category=10的行(假设有150k行(
- 我将更新120k行,并需要删除30k行
第一个想法:当前我正在使用所有行的开始更新为0,更新时将此值更改为1。然后删除category=10和update=0的所有行。
在类别=10的情况下,将150k行更新为0的性能存在问题。有时需要30秒,因为可能有20公里的行,而不仅仅是30公里。
第二个想法一开始,循环所有150k行以保持数组中的id,然后用更新的id填充一个新数组,最后使用array_diff获取要删除的剩余id。
使sql类似于"…"的性能也存在问题;。。。其中id在(…30k ids…(中";。
你们用更好的方法来解决这个问题吗?谢谢
第一个想法的变体:将标志列定义为时间戳,而不是布尔值,然后不必花30秒将其初始化为0。只需在更新行时将时间戳更新为NOW((。完成后,任何标志列比第一个更新行旧的行都应该被删除。我假设这个更新/删除任务将定期再次执行,但只要任务不重叠,时间戳就应该仍然有效。
第二个想法的变体:不要运行查询DELETE FROM imagine WHERE id IN(...30k ids...)
谓词。相反,您可以运行一系列DELETE FROM imagine WHERE id IN (...100 ids...)
。循环浏览您的id列表,并一次以100个为一批进行删除。您需要以这种方式运行300个DELETE语句,但编写循环很容易。
解决方案1bis,如果您正在寻找性能
通常添加一个默认值为0的新字段要比更新现有字段的30K行快。
最后您可以删除这个字段,这也是一个快速命令。
大型更新(或删除(成本高昂,因为在崩溃时需要保存旧行。
如果这是一项一次性任务并且您不需要担心在更新期间阻塞其他活动,那么只需执行查询,并在必要时让查询耗时几分钟。
如果您有其他限制,请具体说明。请提供SHOW CREATE TABLE
,以及建议的更新和删除声明。
对于某些情况,最好使用PRIMARY KEY
浏览表格。一次做1000行。也就是说,首先找到跨越该范围的id的范围,然后执行每个Updates和Deletes,但将(通过WHERE
(限制在该范围内。(在某些情况下,他们可能不修改任何行,但这没关系。(每个块之后的COMMIT
。
更多详细信息:http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks