SQL Server中Timestamp列作为主键的批量插入性能问题咨询
Timestamp/rowversion的生成机制开销
Timestamp(现官方推荐称rowversion)的值由SQL Server在插入时自动生成,而非应用指定。使用SqlBulkCopy批量插入时,每条记录都需要数据库单独计算生成Timestamp值,这会带来额外的CPU与IO开销。在小批量数据场景下,这种单条记录的额外开销占比极高,直接拉低了整体性能。而identity列支持批量分配值,SQL Server可以一次性为一批记录预分配连续的identity值,单条记录的生成成本几乎可以忽略,小批量时优势显著。主键索引的维护差异
尽管两者都是8字节的递增数值,但Timestamp的生成是插入时实时完成的,identity则可提前批量分配。对于聚集主键索引来说,递增值的插入本应是追加到索引末尾,但Timestamp的实时生成会导致索引页的锁竞争更频繁——小批量插入时,每一条记录都要等待Timestamp生成并完成索引更新,锁等待的累积开销被放大。当数据量达到阈值后,索引页填充、磁盘IO等整体开销成为性能主导,锁竞争的相对占比被稀释,两者性能差距自然缩小。SqlBulkCopy的优化适配差异
SqlBulkCopy针对identity列有专门的优化逻辑,比如支持SqlBulkCopyOptions.KeepIdentity参数,或是让数据库自动批量生成identity值,内部处理效率更高。但Timestamp作为主键时,数据库无法对其进行批量生成优化,必须逐行处理,这种处理方式在小批量场景下的性能劣势被放大。当数据量足够大时,批量操作的整体IO开销成为核心瓶颈,逐行生成Timestamp的相对影响就变得不明显了。设计初衷偏离带来的性能损失
Timestamp/rowversion的设计目的是跟踪行的修改版本,用于并发更新时的一致性校验,并非作为主键使用。SQL Server没有针对“Timestamp作为主键”这种场景做性能优化,而identity是专门为代理主键设计的特性,从底层实现到上层优化都更贴合主键的使用需求。
内容的提问来源于stack exchange,提问作者Martin

