2012-09-19 72 views
0

我正在使用Linq查詢MS CRM 2011 Web服務。我有一個查詢導致非常差的SQL,它會獲取太多的中間數據,並且它的性能很糟糕!我是新來的,所以它很可能是我使用它的方式......使用N-N連接以PredicateBuilder優化Linq查詢

我有通過N-N關係鏈接兩個實體:ProductSalesLink。我想從他們的SerialNumber以及與之相關的所有SalesLink中恢復一堆Product

這是我使用PredicateBuilder查詢:

// Build inner OR predicate on Serial Number list 
var innerPredicate = PredicateBuilder.False<Xrm.c_product>(); 
foreach (string sn in serialNumbers) { 
    string temp = sn; // This temp assignement is important! 
    innerPredicate = innerPredicate.Or(p => p.c_SerialNumber == temp); 
} 

// Combine predicate with outer AND predicate 
var predicate = PredicateBuilder.True<Xrm.c_product>(); 
predicate = predicate.And(innerPredicate); 
predicate = predicate.And(p => p.statecode == (int)CrmStateValueType.Active); 

// Inner Join Query 
var prodAndLinks = from p in orgContext.CreateQuery<Xrm.c_product>().AsExpandable() 
                    .Where(predicate) 
                    .AsEnumerable() 
        join link in orgContext.CreateQuery<Xrm.c_saleslink>() 
         on p.Id equals link.c_ProductSalesLinkId.Id 
        where link.statecode == (int)CrmStateValueType.Active 
        select new { 
         productId = p.Id 
         , productSerialNumber = p.c_SerialNumber 
         , accountId = link.c_Account.Id 
         , accountName = link.c_Account.Name 
        }; 
... 

使用SQL事件探查器,我看到了,它會導致一個沒有WHERE子句的中間SQL查詢,看起來像這樣:

select 
top 5001 "c_saleslink0".statecode as "statecode" 
    ... 
, "c_saleslink0".ModifiedOnBehalfByName as "modifiedonbehalfbyname" 
, "c_saleslink0".ModifiedOnBehalfByYomiName as "modifiedonbehalfbyyominame" 
from 
c_saleslink as "c_saleslink0" order by 
"c_saleslink0".c_saleslinkId asc 

這會返回大量的(無用的)數據。我認爲加入是在客戶端而不是在數據庫端完成的...

我應該如何改進此查詢?我跑了大約3分鐘,這是完全不能接受的。

謝謝。


「解決方案」

基於Daryl的答案使用QueryExpression,而不是LINQ到CRM,我得到這個它得到完全相同的結果。

var qe = new QueryExpression("c_product"); 
qe.ColumnSet = new ColumnSet("c_serialnumber"); 
var filter = qe.Criteria.AddFilter(LogicalOperator.Or); 
filter.AddCondition("c_serialnumber", ConditionOperator.In, serialNumbers.ToArray()); 
var link = qe.AddLink("c_saleslink", "c_productid", "c_productsaleslinkid"); 
link.LinkCriteria.AddCondition("statecode", ConditionOperator.Equal, (int)CrmStateValueType.Active); 
link.Columns.AddColumns("c_account"); 
var entities = serviceProxy.RetrieveMultiple(qe).Entities.ToList();; 

var prodAndLinks = entities.Select(x => x.ToEntity<Xrm.c_product>()).Select(x => 
        new { 
         productId = x.c_productId 
        , productSerialNumber = x.c_SerialNumber 
        , accountId = ((Microsoft.Xrm.Sdk.EntityReference)((Microsoft.Xrm.Sdk.AliasedValue)x["c_saleslink1.c_account"]).Value).Id 
        , accountName = ((Microsoft.Xrm.Sdk.EntityReference)((Microsoft.Xrm.Sdk.AliasedValue)x["c_saleslink1.c_account"]).Value).Name 
        }).ToList(); 

我真的也喜歡找使用LINQ的解決方案,但它似乎LINQ到CRM只是現在還沒有...

+0

我沒有用PredicateBuilder成功的CRM,但你可能想看看我的答案(使用動態Linq)和接受的答案(使用PredicateBuilder)的問題[如何獲得今天的所有生日?](http://stackoverflow.com/questions/10142724/how-to-get-all-the-birthdays今天/ 10146065#10146065)成功實現你正在嘗試做的事情。 –

+0

我的回答是否回答你的問題? – Daryl

+0

@Daryl:是的,這樣做,謝謝。我本來喜歡Linq to CRM解決方案,但除了在兩個較小的查詢中分解我的查詢外,我沒有成功...... LINQ到CRM似乎並不支持'WHERE IN'。 – dstj

回答

1

95%的時間在CRM中出現複雜查詢時出現性能問題時,提高性能的最簡單方法是對數據庫運行直接的SQL查詢(假設這不是CRM在線當然)。這可能是5%的時間之一。

就你而言,你遇到的主要性能問題是由於謂詞生成器強制CRM服務器(而不是SQL數據庫)側連接數據。如果你使用了查詢表達式(這是你的鏈接語句被轉換的),你可以用一個IN運算符指定一個條件表達式,它允許你傳入你的serialNumbers集合。你也可以使用FetchXml。這兩種方法都允許CRM執行SQL端連接。

編輯:

這應該讓你與查詢表達式的方式80%:

IOrganizationService service = GetService(); 
var qe = new QueryExpression("c_product"); 
var filter = qe.Criteria.AddFilter(LogicalOperator.Or); 
filter.AddCondition("c_serialnumber", ConditionOperator.In, serialNumbers.ToArray()); 
var link = qe.AddLink("c_saleslink", "c_productid", "c_productsaleslinkid"); 
link.LinkCriteria.AddCondition("statecode", ConditionOperator.Equal, (int)CrmStateValueType.Active); 
link.Columns.AddColumns("c_Account"); 
var entities = service.RetrieveMultiple(qe).Entities.ToList(); 
+0

這是一個更好的解釋我最初的意思。 –

+0

哇,我沒有看到它有一個複雜的查詢。這是我找到的相當簡單的一個。無論如何,我不知道如何構建FetchXml xml,也不使用查詢表達式,但我會試一試... – dstj

+1

@dstj當你開始使用謂詞構建器時,你肯定會提高併發症水平對於CRM來說。 SQL本身並不那麼複雜。 – Daryl

0

你也許會發現,你可以通過不使用得到較好的控制Linq to Crm。你可以嘗試:

  1. FetchXml,這是一個XML語法,在方法上類似於TSQL MSDN

  2. QueryExpressionMSDN

  3. 您可以發出RetrieveRequestblog

+0

你有什麼證據支持這種說法「你可能會發現你可以通過不使用Linq to Crm來獲得更好的性能」? –

+0

表現可能是錯誤的詞,我想我真的是指控制。 –

+0

我打算叫你抄襲,http://stackoverflow.com/a/12413323/227436,但後來我看了兩遍,並意識到這是你的答案以及... :) – Daryl