簡體   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