我有一个包含10列的表,在该表中我有数千/数百万行。 在某些情况下,我希望一次更新超过10K的记录。目前我的方案代码按顺序工作,如
for i in (primary key ids for all records to be updated)
executeupdate(i)
我认为不是运行相同的查询10K次,我将在字符串中添加所有ID并运行单个更新查询,如,
executeupdate(all ids)
实际的数据库查询可以是这样的,
假设我有主键ID,
10001,10002,10003,10004,10005
所以在第一种情况下我的查询就像
update tab1 set status="xyz" where Id="10001"
update tab1 set status="xyz" where Id="10002"
update tab1 set status="xyz" where Id="10003"
update tab1 set status="xyz" where Id="10004"
update tab1 set status="xyz" where Id="10005"
和我的批量更新查询类似,
update tab1 set status="xyz" where id in ("10001","10002","10003","10004","10005")
所以我的问题是,我是否会通过批量更新获得任何性能提升(执行时间) 或者总查询执行时间与每个记录索引扫描相同,并且会发生更新吗?
注意:我使用DB2 9.5作为数据库
感谢。
答案 0 :(得分:3)
通常,无论数据库如何,“批量”更新都会更快。当然,你可以测试两者的表现,并报告回来。
在处理查询方面,每次调用update
都需要大量开销,在表/页/行上设置锁定。执行单个更新可以巩固此开销。
单个update
的缺点是整体可能更快,但可能会在更长的时间内锁定底层资源。例如,单个更新可能每个需要10毫秒,其中1000个的经过时间为10秒。但是,没有资源被锁定超过10毫秒。批量更新可能需要5秒钟,但资源将在此期间的更长时间内被锁定。
要加快这些更新,请确保已将id
编入索引。
我应该注意。这是一般原则。我没有专门测试DB2上的单个更改性能与多个更新性能。
答案 1 :(得分:1)
您肯定会看到性能提升,因为您将减少往返次数。
然而,这种方法不能很好地扩展;在一个声明中成千上万的ID可能会有点棘手。此外,查询的大小也有限制(可能是64k)。您可以考虑通过表格“页面”并更新 - 例如 - 每个更新语句100个记录。
答案 2 :(得分:0)
如果您正在使用.NET(并且在Java等其他语言中可能有类似的选项),您可以在名为BeginChain
的DB2Connection类上使用该选项,这将极大地提高性能
基本上,当您激活链选项时,您的DB2客户端会将所有命令保留在队列中。当您拨打EndChain
时,队列将立即发送到服务器,并一次处理。
文档说这应该比非链式UPDATE
/ INSERT
/ DELETE
更好(这是我们在我店里看到的),但是你可能需要注意一些差异:
ExecuteNonQuery
将返回-1
。此外,通过使用带参数标记的查询而不是单独的单个查询,可以进一步提高性能(假设状态也可以更改,否则,您可能只使用文字):
UPDATE tab1
SET status = @status
WHERE id = @id
编辑评论:我不确定是否混淆使用Parameter Markers(它们只是查询中值的占位符,有关详细信息,请参阅链接) ,或在链接的实际使用中。如果是第二个,那么这里是一些示例代码(我没有验证它是否有效,因此请自担风险使用:)
):
//Below is a function that returns an open DB2Connection
//object. It can vary by shop, so put it whatever you do.
using (var conn = (DB2Connection) GetConnection())
{
using (var trans = conn.BeginTransaction())
{
var sb = new StringBuilder();
sb.AppendLine("UPDATE tab1 ");
sb.AppendLine(" SET status = 'HISTORY' ");
sb.AppendLine(" WHERE id = @id");
trans.Connection.BeginChain();
using (var cmd = trans.Connection.CreateCommand())
{
cmd.CommandText = sb.ToString();
cmd.Transaction = trans;
foreach (var id in ids)
{
cmd.Parameters.Clear();
cmd.Parameters.Add("@id", id);
cmd.ExecuteNonQuery();
}
}
trans.Connection.EndChain();
trans.Commit();
}
}
答案 3 :(得分:0)
我想指出的另一个方面是提交间隔。如果单个更新语句更新少量100 K行,则事务日志也会相应增长,可能会变慢。我已经看到使用ETL工具(例如informatica)的总时间减少了,这些工具在每个记录之后发送了一组更新语句,然后是一个提交 - 与基于条件的单个更新语句相比,它在单个go中完成。这对我来说是违反直觉的。
答案 4 :(得分:0)
一周前我带着同样的问题来到这里。然后我遇到了一种情况,我不得不通过JDBC更新mySQL数据库中大约3500行的表。 我更新了相同的表两次:一次通过For循环,迭代一组对象,一次使用批量更新查询。以下是我的发现:
要回答这个问题,让我们看看查询是如何在DBMS中实际执行的。
与过程语言不同,您指示DBMS做什么,但不指导如何做。 DBMS然后执行以下操作。
现在,当您逐行更新数据库中的表时,您执行的每个查询都将通过解析,优化和执行。相反,如果你编写一个循环来创建一个相当长的查询,然后执行相同的查询,它只被解析一次。使用批量更新代替迭代方法节省的时间量随着更新的行数几乎呈线性增加。