我正在尝试找出最有效的查询列表的方法。我知道那里有大量的例子,之前已经出现过这样的问题,但我真的很陌生,我正在努力解决如何将一些概念应用到我的情况中。
private static void KeepMatchesBasedOnRestrictions(ref List<Entity> matches,
List<Entity> preFilteredShifts, List<Entity> locationalInformations)
{
if (matches.Count == 0) return;
matches.RemoveAll(
(match) => ( GeographyHasRestriction(match, preFilteredShifts, locationalInformations) )
);
}
private static bool GeographyHasRestriction(Entity match, List<Entity> preFilteredShifts, List<Entity> locationalInformations)
{
EntityReference fw = match.GetAttributeValue<EntityReference>("crm_fw");
Entity shift = preFilteredShifts.Single<Entity>(
a => match.GetAttributeValue<EntityReference>("crm_shift").Id == a.Id
);
EntityReference trust = shift.GetAttributeValue<EntityReference>("crm_trust");
EntityReference location = shift.GetAttributeValue<EntityReference>("crm_location");
EntityReference ward = shift.GetAttributeValue<EntityReference>("crm_ward");
Dictionary<Guid, Entity> locInfoRecs = locationalInformations.ToDictionary(p => p.Id);
var locationalInformationQuery = from loc in locationalInformations
where (
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& !loc.Contains("crm_trust")
&& !loc.Contains("crm_location")
&& !loc.Contains("crm_ward")
)
||
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& loc.GetAttributeValue<EntityReference>("crm_trust").Id == trust.Id
&& !loc.Contains("crm_location")
&& !loc.Contains("crm_ward")
)
||
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& loc.GetAttributeValue<EntityReference>("crm_trust").Id == trust.Id
&& loc.GetAttributeValue<EntityReference>("crm_location").Id == location.Id
&& !loc.Contains("crm_ward")
)
||
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& loc.GetAttributeValue<EntityReference>("crm_trust").Id == trust.Id
&& loc.GetAttributeValue<EntityReference>("crm_location").Id == location.Id
&& loc.GetAttributeValue<EntityReference>("crm_ward").Id == ward.Id
)
)
select loc;
foreach (Entity loc in locationalInformationQuery)
{
if (loc.GetAttributeValue<bool>("crm_hasrestriction"))
{
return true;
}
}
//return false;
}
所以我认为我的问题是2倍;
locationalInformationQuery
查询似乎运行得非常缓慢...我在每次迭代最多2秒的时间内谈论一些非常糟糕的事情。matches.RemoveAll()
的方法也存在一些缺陷。因此,就解决此问题而言,我认为通过将locationalInformations
list
转换为其他类型的容器(例如Dictionary
,{},我可以获得更好的效果{1}}或HashSet
。我的问题是我不知道如何调整我的查询以利用那些更有效的容器。
就第二点而言,我也很想知道使用SortedList
的替代方法。我可以灵活地修改我的传入容器类型,因为这可能是可行的。
关于列表大小,如果有任何用途,匹配包含几千个项目,List.RemoveAll()
和preFilteredShifts
每个包含&gt; 100,000件物品。
另外,我尝试使用locationalInformations
代替Parallel.ForEach
,但它几乎没有任何区别。
编辑:为了澄清一些问题,我正在记忆中做这一切。我已经完全填充了我的所有列表,所以不应再有任何往返DB的往返。我有理由相信foreach
不会进一步增加数据库开销。
此外,是的,这是一个调用Dynamics CRM Online的本地应用程序。
答案 0 :(得分:0)
代码 -
foreach (Entity loc in locationalInformationQuery)
{
if (loc.GetAttributeValue<bool>("crm_hasrestriction"))
{
return true;
}
}
可能是缓慢的一个原因。您正在获取更多数据,然后在内存中枚举它们。您可以在获取之前直接执行检查,这样您将获取较少的数据并且可以更快。像这样的东西 -
return (from loc in locationalInformations
where ((
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& !loc.Contains("crm_trust")
&& !loc.Contains("crm_location")
&& !loc.Contains("crm_ward")
)
||
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& loc.GetAttributeValue<EntityReference>("crm_trust").Id == trust.Id
&& !loc.Contains("crm_location")
&& !loc.Contains("crm_ward")
)
||
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& loc.GetAttributeValue<EntityReference>("crm_trust").Id == trust.Id
&& loc.GetAttributeValue<EntityReference>("crm_location").Id == location.Id
&& !loc.Contains("crm_ward")
)
||
(
loc.GetAttributeValue<EntityReference>("crm_fw").Id == fw.Id
&& loc.GetAttributeValue<EntityReference>("crm_trust").Id == trust.Id
&& loc.GetAttributeValue<EntityReference>("crm_location").Id == location.Id
&& loc.GetAttributeValue<EntityReference>("crm_ward").Id == ward.Id
)
) && loc.GetAttributeValue<bool>("crm_hasrestriction")) // do the check before fetch in here
select loc).Any();
答案 1 :(得分:0)
我偶尔发现,当您使用的查询足够复杂时,查询CRM数据库会导致查询效率低下。
有时这可能是由于查询的生成方式取决于查询数据库的方法,有时可能是迭代某些IEnumerable类型集合并且检查条件会导致每次迭代对数据库进行许多SQL查询。也许使用SQL事件探查器检查数据库中正在发生的事情。它可能会变得富有洞察力。
我有时会恢复的一个选项,我觉得CRM query limitations只是简单地妨碍了性能,是针对我可以访问查询计划的过滤视图直接回到ADO.NET和SQL更好的想法和对正在发生的事情的理解。我相信很多CRM纯粹主义者现在都对我皱眉,但我认为就最终用户体验而言,这也是一个公平的调用,也使你的代码也相对容易理解。复杂的查询在代码中可能非常笨拙,并且您可以参考SQL查询,可以帮助您理解您的解决方案。您还可以从基于集合的操作中受益,并在结果数据库调用的数量方面获得较少的“聊天”界面。
在上面的问题中,如果您认为这可能是一个不错的选择,我会通过提供类似的方法来研究这种解决方案的原型;
private static bool GeographyHasRestrictionBySql(Entity match, List<Entity> preFilteredShifts, List<Entity> locationalInformations)
{
// Query here, and determine your boolean result to return
}
通过改变调用函数,您可以通过这种方式快速轻松地测试它。