RavenDB调用SaveChanges耗时过长及$id/changeVector异常问题咨询
RavenDB SaveChanges() 性能优化与变更异常问题解答
问题1:未修改对象却触发大量$id变更导致SaveChanges()缓慢
原因
RavenDB客户端的变更检测依赖对象引用与属性值对比。当加载包含带$id的嵌套独立文档的复杂对象时,反序列化会重新创建嵌套对象实例——即使$id值未变,客户端也会因引用不同误判为属性变更。100个含500+嵌套对象的Solutionpage会生成数千条无效变更记录,导致SaveChanges()处理大量无意义更新,耗时剧增。
优化方案
按需启用变更跟踪
加载无需修改的文档时,使用NoTracking()关闭客户端跟踪,避免无效变更检测:// 加载只读文档,不跟踪变更 var readOnlyPages = session.Query<Solutionpage>() .Take(100) .NoTracking() .ToList(); // 仅对需修改的文档启用跟踪 var targetPage = session.Load<Solutionpage>("solutionpages/123"); targetPage.Title = "Updated Title";将嵌套对象改为纯嵌入式结构
若items无需作为独立文档(无需单独查询/修改),移除其$id字段,定义为普通嵌入式对象。客户端会仅跟踪父文档变更,不再处理嵌套对象的$id检测:// 修改前(嵌套独立文档) public class Item { public string $id { get; set; } public List<Detail> List1 { get; set; } public List<Detail> List2 { get; set; } public List<Detail> List3 { get; set; } } // 修改后(纯嵌入式对象) public class Item { public List<Detail> List1 { get; set; } public List<Detail> List2 { get; set; } public List<Detail> List3 { get; set; } }手动忽略无效变更
若必须保留嵌套文档结构,可忽略无需修改对象的变更:foreach (var page in solutionPages) { // 忽略整个页面的变更 session.Advanced.IgnoreChangesFor(page); // 仅对需要修改的item取消忽略 foreach (var item in page.Items.Where(i => i.RequiresUpdate)) { session.Advanced.UnignoreChangesFor(item); } }
问题2:刚加载的文档SaveChanges()后changeVector变化
原因
当客户端误报变更(如$id字段的无效变更),会向服务器发送更新请求。即使文档实际数据未变,RavenDB仍会生成新的changeVector——因为changeVector记录了文档版本历史,任何写入操作(包括无数据变更的请求)都会更新版本信息。若嵌套文档被误判为变更,服务器处理其更新后,父文档的changeVector也会随之更新。
解决办法
通过上述问题1的方案消除无效变更后,未修改的文档不会触发更新请求,changeVector将保持不变。也可在SaveChanges()前调用session.Advanced.WhatChanged()检查变更记录,提前排除误报的$id变更。
内容的提问来源于stack exchange,提问作者Bilal lilla
相关产品推荐
相关产品推荐

