更新大型表上的行的最高效方法
Posted
技术标签:
【中文标题】更新大型表上的行的最高效方法【英文标题】:Most performant way to update rows on large tables 【发布时间】:2021-12-05 22:08:32 【问题描述】:我有 2 张桌子:
请求:
idㅤㅤ|ㅤㅤaccountㅤㅤㅤㅤ|ㅤsubaccountㅤ|ㅤamountㅤ|ㅤㅤupdatedAmount
1ㅤㅤ|ㅤㅤACCOUNT_1ㅤㅤ|ㅤㅤㅤ12ㅤㅤㅤ|ㅤㅤ10.2ㅤㅤ|ㅤㅤnull
2ㅤㅤ|ㅤㅤACCOUNT_2ㅤㅤ|ㅤㅤㅤ45ㅤㅤㅤ|ㅤㅤ0ㅤㅤㅤ|ㅤㅤnull
3ㅤㅤ|ㅤㅤACCOUNT_3ㅤㅤ|ㅤㅤㅤ11ㅤㅤㅤ|ㅤㅤ50.6ㅤㅤ|ㅤㅤnull
每日数据:
idㅤㅤ|ㅤㅤaccountㅤㅤㅤㅤ|ㅤsubaccountㅤ|ㅤamountㅤ
1ㅤㅤ|ㅤㅤACCOUNT_1ㅤㅤ|ㅤㅤㅤ45ㅤㅤㅤ|ㅤㅤ3.12
2ㅤㅤ|ㅤㅤACCOUNT_1ㅤㅤ|ㅤㅤㅤ12ㅤㅤㅤ|ㅤㅤ15
3ㅤㅤ|ㅤㅤACCOUNT_2ㅤㅤ|ㅤㅤㅤ11ㅤㅤㅤ|ㅤㅤ1.09
4ㅤㅤ|ㅤㅤACCOUNT_2ㅤㅤ|ㅤㅤㅤ70ㅤㅤㅤ|ㅤㅤ30.6
5ㅤㅤ|ㅤㅤACCOUNT_3ㅤㅤ|ㅤㅤㅤ11ㅤㅤㅤ|ㅤㅤ50.6
我需要更新 Request 表中的 updatedAmount 列,满足以下条件:
-仅当它在 DailyData 表中找到具有相同帐户和子帐户的行时才更新行。 - 仅当每个表中列数量的值不同时才会更新。
对于符合此条件的行,它将金额(来自 DailyData 表)保存在 updatedAmount(请求表)列中。
所以对于这个例子,我们会有这个输出,只有 id 1 更新:
idㅤㅤ|ㅤㅤaccountㅤㅤㅤㅤ|ㅤsubaccountㅤ|ㅤamountㅤ|ㅤㅤupdatedAmount
1ㅤㅤ|ㅤㅤACCOUNT_1ㅤㅤ|ㅤㅤㅤ12ㅤㅤㅤ|ㅤㅤ10.2ㅤㅤ|ㅤㅤ15
2ㅤㅤ|ㅤㅤACCOUNT_2ㅤㅤ|ㅤㅤㅤ45ㅤㅤㅤ|ㅤㅤ0ㅤㅤㅤ|ㅤㅤnull
3ㅤㅤ|ㅤㅤACCOUNT_3ㅤㅤ|ㅤㅤㅤ11ㅤㅤㅤ|ㅤㅤ50.6ㅤㅤ|ㅤㅤnull
我最大的问题是性能。这是一个日常流程,Request 表将有超过 100 万行,而 DailyProcess 表大约有 300k 行,每天都在变化。 到目前为止,我创建了 2 个方法,但都需要很多时间。
1:
UPDATE Request r
LEFT OUTER JOIN DailyData d
ON r.account = d.account AND r.subaccount = d.subaccount
SET r.updatedAmount = d.amount
2:
UPDATE Request r, DailyData d
SET r.updatedAmount = d.amount
WHERE r.account = d.account AND r.subaccount = d.subaccount AND r.amount <> d.amount
有人能推荐更快的方法吗?任何帮助将不胜感激
【问题讨论】:
您创建了哪些索引?两个表上的帐户/子帐户的复合索引可能会有所帮助。 查看(并在此处分享)query plans used。这将表明查询是否可以从新索引(以及哪些索引)或其他调整中受益,以鼓励不同的计划。 查询计划选择有时还会显示其他工件,例如由于统计信息错误而从良好候选索引中选择的错误计划。还应更新问题以包含所有当前索引,作为所示架构的一部分。 最后,显示的两种更新方法具有不同的行为(第一次更新将为 DailyData 中缺失的项目分配 NULL 金额;它还将导致所有 Request 记录更新,即使值相同)。哪种行为是正确的? 【参考方案1】:我的意思是你可以使用INNER JOIN
UPDATE Request r
INNER JOIN DailyData d
ON r.account = d.account AND r.subaccount = d.subaccount
SET r.updatedAmount = d.amount
WHERE r.amount <> d.amount;
可以通过为两个表创建索引(帐户、子帐户)来提高更新性能
【讨论】:
(fwiw 在 mysql 上,LEFT join 莫名其妙地几乎总是比 INNER JOIN 快,还没有听到关于为什么的令人信服的理论,但它每次都赢得了基准测试) 原始查询中的 LEFT OUTER 连接可能是也可能不是错误(尤其是两个已发布查询之间的行为不同时)。但是,使用 INNER 连接会改变行为,因此应明确提及此类行为,以便使用正确的(按预期结果)行为。以上是关于更新大型表上的行的最高效方法的主要内容,如果未能解决你的问题,请参考以下文章