最高效(&最快)查询列表的方法

本文关键字:查询 列表 方法 最快 高效 | 更新日期: 2023-09-27 17:53:09

我正试图找出最高效的方式来查询列表。我知道有很多这样的例子,以前也遇到过很多,但我真的是新手,我正在努力解决如何将一些概念应用到我的情况中。

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

所以我认为我的问题是双重的;

  1. locationalInformationQuery查询似乎运行得很慢…我说的是每次迭代长达2秒的东西,这太可怕了。
  2. 我也怀疑调用matches.RemoveAll()的方法也有一些缺陷,因为关于列表的性能问题。

因此,就解决这个问题而言,我认为我可以通过将我的locationalInformations list转换为其他类型的容器(如Dictionary, HashSetSortedList)来获得更好的性能。我的问题是,我不知道如何去调整我的查询,以利用那些更有效的容器。

就第二点而言,我也很想知道使用List.RemoveAll()的替代方案。在合理可行的情况下,我可以灵活地修改传入的容器类型。

关于列表的大小,match包含几千个项目,preFilteredShiftslocationalInformations每个包含> 100,000个项目。

作为题外话,我曾尝试使用Parallel.ForEach而不是foreach,但它几乎没有任何区别。

编辑:只是为了澄清一些问题,我在记忆中做了所有这些。我已经完全填充了我所有的列表,所以不应该有任何额外的往返数据库。我有理由肯定GetAttributeValue<EntityReference>不会初始化进一步的数据库开销。

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

最高效(&最快)查询列表的方法

代码

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(); 

我有时发现,当您正在处理的查询非常复杂时,查询CRM数据库可能会导致查询效率低下。

有时,这可能是由于查询的生成方式取决于查询数据库的方法,或者有时可能是迭代一些IEnumerable类型集合和检查条件会导致每次迭代对数据库进行许多SQL查询。也许可以通过使用SQL Profiler来检查数据库背后发生的事情。它可能会很有见地。

当我觉得CRM查询限制对性能的影响太大时,我偶尔会回到直接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
}

这样,您就可以通过更改调用函数来快速轻松地进行测试。