Azure Service Fabric 可靠字典 LINQ 查询非常缓慢。

4

我在Service Fabric有一个可靠的字典状态服务。我有一个简单的linq表达式。
我正在使用Ix-Async包构建一个异步可枚举。


using (ITransaction tx = this.StateManager.CreateTransaction())  
        {  

          var result = (await customers.CreateLinqAsyncEnumerable(tx))
                .Where(x => x.Value.NameFirst != null && x.Value.NameFirst.EndsWith(n, StringComparison.InvariantCultureIgnoreCase))
                    .Select(y => y.Value);

           return await result.ToList();


        }  

这些数据被分为两个分区,每个分区大约有75000条记录。我使用Int64范围作为分区键。在上面的代码中,“Result.ToList()”需要大约1分钟来执行每个分区。另一个奇怪的事情是,实际结果为空!虽然在SQL Server中运行相同的SQL可以返回以“c”结尾的客户名字的行,但这并不重要。我最担心的是“ReliableDictionary” Linq查询的性能问题。
谢谢


记录有多大?你在什么硬件上运行它?你是在本地开发机上进行测量,还是在真正的集群上进行的?同一台机器上是否有其他服务?你尝试过不使用Ix-Async包进行枚举,看看是否有任何差异吗? - Vaclav Turecek
该表是一个标准表,唯一的区别是它有一个二进制列[图片]。这是一个本地开发集群,具有16 GB的内存。向字典插入记录非常快速(每分钟约2000条记录)。通过键进行字典查找也非常迅速。我使用异步枚举器遍历了整个75,000条记录,并应用了谓词,但仍然需要大约50秒。 - teeboy
如果它在本地开发机上,两个分区都共享同一台物理机器,因此实际上您正在同时拉取两组75,000。 - Vaclav Turecek
1
另外,出于好奇,SQL Server 有列索引。如果在存储为可靠字典的序列化 POCO 上未定义基于属性的索引,那么如何使 LINQ 对对象查询快速?内部查询搜索字典必须进行完整的集合扫描,对吗? - teeboy
在我看来,只有2个分区是相当糟糕的选择,这样你会面临所有的惩罚,但却没有任何好处。我建议至少采用6-8个分区,并进行并行查询。根据梅特的评论,我们通常使用内存索引。 - user1496062
显示剩余2条评论
1个回答

7
可靠字典 Reliable Dictionary 定期从内存中删除最近不使用的值。这样可以实现以下目标:
  • 大型可靠字典
  • 更高的密度:每个副本中可靠集合的密度更高,每个节点中副本的密度更高。
然而,这样做会增加读取延迟:需要进行磁盘 I/O 来检索内存中未缓存的值。有几种选项可使枚举速度更快:

1) 键过滤枚举: 将要在查询中使用的字段移动到 ReliableDictionary 的 TKey 中(如上例中的 NameFirst)。这将使您能够使用CreateEnumerbleAsync 带有键过滤器的重载。键过滤器允许 Reliable Dictionary 避免为与查询不匹配的键检索值。这种方法的一个限制是 TKey(因此其中的字段)不能被更新。

2) 使用通知的内存中辅助索引: 可以使用Reliable Dictionary Notifications 构建任意数量的辅助索引。您可以构建一个辅助索引,将所有值保留在内存中,从而消耗内存资源以提供更低的读取延迟。此外,由于您完全控制辅助索引,因此可以使其有序(例如按照示例中 NameFirst 的相反顺序)。

我们还考虑使可靠字典的内存中 TValue 扫描策略可配置。这样,如果读取延迟是优先考虑因素,则可以将 Reliable Dictionary 配置为将所有值保留在内存中。

由于在您的情况下枚举大部分时间都花费在磁盘 I/O 上,因此您还可以受益于使用自定义序列化器,这可以减少磁盘和网络占用。

感谢您的提问。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接