繁体   English   中英

查询列表的最有效(最快)方式

[英]Most efficient (& fastest) way to query a list

我正在尝试找出最高效的方法来查询列表。 我知道那里有很多示例,以前这已经很繁重了,但是我对此确实很陌生,并且我在努力将某些概念应用于我的处境而苦苦挣扎。

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()方法也存在一些缺陷。

因此,在解决此问题方面,我认为我可以通过将locationalInformations list转换为其他类型的容器(例如DictionaryHashSetSortedList来获得更好的性能。 然后我的问题是我不知道如何调整查询以利用那些更有效的容器。

至于第二点,我也很想知道使用List.RemoveAll()替代方法。 我可以灵活地修改传入的容器类型,以使其可行。

关于列表大小(在任何使用情况下),match包含数千个项目, preFilteredShiftslocationalInformations每个包含> 100,000个项目。

foreach ,我尝试使用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
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM