查询列表

时间:2015-06-02 23:16:55

标签: c# performance dynamics-crm

我正在尝试找出最有效的查询列表的方法。我知道那里有大量的例子,之前已经出现过这样的问题,但我真的很陌生,我正在努力解决如何将一些概念应用到我的情况中。

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倍;

  1. locationalInformationQuery查询似乎运行得非常缓慢...我在每次迭代最多2秒的时间内谈论一些非常糟糕的事情。
  2. 我还怀疑,由于有关列表的性能问题,调用matches.RemoveAll()的方法也存在一些缺陷。
  3. 因此,就解决此问题而言,我认为通过将locationalInformations list转换为其他类型的容器(例如Dictionary,{},我可以获得更好的效果{1}}或HashSet。我的问题是我不知道如何调整我的查询以利用那些更有效的容器。

    就第二点而言,我也很想知道使用SortedList的替代方法。我可以灵活地修改我的传入容器类型,因为这可能是可行的。

    关于列表大小,如果有任何用途,匹配包含几千个项目,List.RemoveAll()preFilteredShifts每个包含&gt; 100,000件物品。

    另外,我尝试使用locationalInformations代替Parallel.ForEach,但它几乎没有任何区别。

    编辑:为了澄清一些问题,我正在记忆中做这一切。我已经完全填充了我的所有列表,所以不应再有任何往返DB的往返。我有理由相信foreach不会进一步增加数据库开销。

    此外,是的,这是一个调用Dynamics CRM Online的本地应用程序。

2 个答案:

答案 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
}

通过改变调用函数,您可以通过这种方式快速轻松地测试它。

相关问题