SQL服务器更新索引设计
我有一个表,用的idMap DML:SQL服务器更新索引设计
CREATE TABLE tempdb2.dbo.idmaptemp (
OldId varchar(20),
CV_ModStamp datetimeoffset,
NewId varchar(20),
RestoreComplete bit,
RestoreErrorMessage varchar(1000),
OperationType varchar(20)
)
当它被定义,它已经包含了一组预定义约(100万)的行。恢复操作完成后,我必须更新表上的NewId,RestoreComplete,RestoreErrorMessage。 的说法是:
update tempdb2.dbo.IdMaptemp set NewId = 'xxx', RestoreComplete = 'false', RestoreErrorMessage = 'error' where OldId = 'ABC';
Java应用程序对内存约一百万值,并与上述语句更新的值。数据库设置为自动关闭,并随批次(批量大小500)而变化。
我曾尝试在索引两个选项与OLDID领域:
聚集索引 - 执行计划列为聚集索引更新(100%的成本)。这是因为叶子是正在更新的行,哪些会触发索引更新。我在这里吗?
非聚集索引 - 执行计划列出更新(75%)和查找(25%)。
是否有任何其他的速度ups可以实现在数据库表上的批量更新?该表不能被更新影响,因此无法清除并重新插入该表。每批500行样本的聚簇索引需要大约7小时更新。
我应该选择非聚集索引选项吗?
更改大表的聚簇索引是一个昂贵的建议。表的聚集索引是为整个表定义的,而不是针对行的子集。
如果您将oldid
作为聚簇索引而仅想提高批处理性能,请考虑允许db参与批处理过程而不是应用程序/ java层。要求db一次更新数百万行1行,这是一个昂贵的建议。用批量填充临时表然后让SQL一次更新整个批处理可以是提高性能的好方法。
insert #temptable (OldId,NewId)
...
Update
set T1.NewId = T2.NewId
T1
from
T1 join #tempTable T2
on T1.OldId = T2.OldId
如果您可以计算新的ID,请考虑另一种批量策略。
update tempdb2.dbo.IdMaptemp top 1000 set NewId = 'xxx', RestoreComplete = 'false',
RestoreErrorMessage = 'error' where NewId is null;
如果你真的想创建NEWID新表的聚集索引 创建新表,只要你喜欢
insert into NewTable()
select top 10000 *
from OldTable O
left join NewTable N
on O.OldId = N.OldId
where N.OldId is null
完成后,删除旧表。
注意:您的ID是否需要20个字节?通常,聚簇索引是int - 4个字节或bigint - 8个字节。
如果这是一次性事情,那么更改大型永久性表上的聚集索引将是值得的。如果oldid将始终处于获取newid值的过程中,并且这只是您拥有的工作流程,但我不打扰更改持久表的聚簇索引。只需将oldid作为聚簇索引即可。 NewId听起来像是代理键。
由于这是一个临时表,所以可以在创建时修改表上的索引。最终,通过加入新的ID,将状态写入数据源表。这似乎是在数据库上更新大量值的永无止境的循环。由于在连接上运行更新,表格是否仍然需要索引?注册。 ID,ID是唯一生成的20个字符,并且是特定于要求的。 – dmachop
再次..我怀疑这是一个操作,可以完全发生在数据库中,它只是在Java中完成,因为这是你喜欢使用的锤子....我可能是错的,但它发生了很多! –
百分比毫无意义,它们只是表明成本如何分配到计划中,它们在计划外没有任何价值。 –
@Mark Rotteveel任何可以找到执行计划需要花费时间的信息? – dmachop
如果您正在解决性能问题,也许您可以将更新从Java迁移到SQL脚本中。您是否在此表上运行了100万个单独的更新语句?如果是这样,您可能会发现很大一部分性能问题是由于各个更新语句而不是任何特定的索引。如果您可以重构流程以在数据库中执行所有这些操作,则会更快。例如,批量将百万个值加载到另一个表中,然后在一个批处理中执行数据库更新。 –