更新具有数百万条记录的表时性能下降

Bha*_*ani 1 postgresql performance update query-performance

我想更新表(我是 20-30 ),每个表都有数百万条记录。

问题是更新过程花费了太多时间,而且那时 CPU 使用率也很高。我想以一种在处理数据时不能使用太多 CPU 的方式来做。如果处理时间增加,那么这对我来说不是问题,但它应该使用有限的 CPU 资源来处理(更新)表。我使用 PostgreSQL 作为数据库,服务器操作系统是 Linux。

我的示例查询可以是这样的

UPDATE TEMP 
SET CUSTOMERNAME = 
  ( select customername from user where user.customerid = temp.customerid );
Run Code Online (Sandbox Code Playgroud)

kgr*_*ttn 10

第一个问题是:为什么不使用大量 CPU 时间很重要?查询会在某些资源上遇到瓶颈;如果您可以引入足够的额外磁盘访问,那么每秒使用的 CPU 时间将会减少,但这真的是一种改进吗?您希望饱和哪种资源?了解您为何强调这一点可能有助于指导人们提供您会发现有用的答案。

正如评论中所建议的那样,您的查询可能会通过连接而不是相关子查询运行得更快。像这样的东西:

UPDATE temp
  SET customername = user.customername
  FROM user
  WHERE user.customerid = temp.customerid;
Run Code Online (Sandbox Code Playgroud)

另一个需要了解的重要事项是您是否要更新表中的所有行。某些值是否已经正确?如果是这样,通过不更新不需要的行,您将获得巨大的性能提升。添加AND temp.customername is distinct from user.customernameWHERE子句。

如果限制每个语句中更新的行数,并且VACUUM ANALYZE在每次 UPDATE 之后,您将避免表膨胀。如果希望最小化 CPU 时间的目的是避免对并发事务的性能影响,这将使您有机会sleep在开始UPDATE一组事务中的下一个之前引入短暂的延迟(以 a或类似的形式)行。

更好的是,为什么要在临时表中冗余存储信息而不是在需要时加入它?(有时有一个很好的理由;很多时候没有。)

  • @BhavikAmbani:如果这不是临时表,您打算如何确保名称在源表中发生名称更改时在其他表中保持最新?如果您标准化为第三范式,则不会有问题。不要相信关于连接缓慢的 FUD——首先规范化,并在遇到实际问题时寻求优化。通常会有比非规范化更好的解决方案。过早的优化会导致很多问题。 (3认同)

HLG*_*GEM 5

如果您遵循了kgrittn 的非常好的建议并且仍然存在性能问题,您可能需要批量执行更新。您仍然会执行基于集合的更新,但将它们限制为前 1000 个(或任何适合您的数字,我已经使用了 500 到 50,000 个)不匹配的记录,然后继续循环直到全部完成。