我正在研究一段由同事編寫的與我們公司使用的CRM應用程序接口的代碼。在這段代碼中有兩個LINQ to Entities查詢在我們的應用程序中被執行了很多次,並且我被要求優化它們,因爲其中一個非常慢。LINQ to Entities查詢需要很長時間才能編譯,SQL運行速度很快
這些都是疑問:
首先查詢,這個編譯幾乎瞬間。它得到相關信息從CRM數據庫,由應用程序給定關係ID的列表過濾:
from relation in context.ADRELATION
where ((relationIds.Contains(relation.FIDADRELATION)) && (relation.FLDELETED != -1))
join addressTable in context.ADDRESS on relation.FIDADDRESS equals addressTable.FIDADDRESS
into temporaryAddressTable
from address in temporaryAddressTable.DefaultIfEmpty()
join mailAddressTable in context.ADDRESS on relation.FIDMAILADDRESS equals
mailAddressTable.FIDADDRESS into temporaryMailAddressTable
from mailAddress in temporaryMailAddressTable.DefaultIfEmpty()
select new { Relation = relation, Address = address, MailAddress = mailAddress };
第二個查詢,需時約4-5秒,以編譯,大約需要從人的信息數據庫(再次ID的列表過濾):
from role in context.ROLE
join relationTable in context.ADRELATION on role.FIDADRELATION equals relationTable.FIDADRELATION into temporaryRelationTable
from relation in temporaryRelationTable.DefaultIfEmpty()
join personTable in context.PERSON on role.FIDPERS equals personTable.FIDPERS into temporaryPersonTable
from person in temporaryPersonTable.DefaultIfEmpty()
join nationalityTable in context.TBNATION on person.FIDTBNATION equals nationalityTable.FIDTBNATION into temporaryNationalities
from nationality in temporaryNationalities.DefaultIfEmpty()
join titelTable in context.TBTITLE on person.FIDTBTITLE equals titelTable.FIDTBTITLE into temporaryTitles
from title in temporaryTitles.DefaultIfEmpty()
join suffixTable in context.TBSUFFIX on person.FIDTBSUFFIX equals suffixTable.FIDTBSUFFIX into temporarySuffixes
from suffix in temporarySuffixes.DefaultIfEmpty()
where ((rolIds.Contains(role.FIDROLE)) && (relation.FLDELETED != -1))
select new { Role = role, Person = person, relation = relation, Nationality = nationality, Title = title.FTXTBTITLE, Suffix = suffix.FTXTBSUFFIX };
我已經設置了SQL事件探查器,並採取了從SQL查詢兩,然後運行它在SQL Server Management Studio中。兩個查詢都運行得非常快,即使有大量(〜1000)個ID。所以問題似乎在於編譯LINQ查詢。
我試圖使用編譯查詢,但由於那些只能包含原始參數,我不得不去除部分與篩選器,並應用Invoke()調用後,所以我不知道如果這幫助很大。此外,由於此代碼在WCF服務操作中運行,因此我不確定編譯後的查詢是否會在後續調用中仍然存在。
最後,我嘗試的是隻在第二個查詢中選擇一個列。雖然這顯然不能提供我需要的信息,但我認爲它會比我們現在選擇的200列更快。沒有這種情況下,它仍然需要4-5秒。我不是一個LINQ大師,所以我幾乎不能遵循這個代碼(我有一種感覺,它不是最佳編寫的,但不能把我的手指放在它上面)。任何人都可以給我提示,爲什麼會出現這個問題?
我剩下的唯一解決方案是手動選擇所有信息而不是加入所有這些表。然後我會以約5-6個查詢結束。不錯,我想,但是由於我沒有在這裏處理可怕的低效SQL(或者至少是可接受的無效率水平),所以我希望能夠避免這種情況。
在此先感謝,希望我能說清楚。如果沒有,請隨時詢問,我會提供更多詳細信息。
編輯: 我結束了我的實體框架添加協會(目標數據庫沒有指定的外鍵)正是如此重寫查詢:
context.ROLE.Where(role => rolIds.Contains(role.FIDROLE) && role.Relation.FLDELETED != -1)
.Select(role => new
{
ContactId = role.FIDROLE,
Person = role.Person,
Nationality = role.Person.Nationality.FTXTBNATION,
Title = role.Person.Title.FTXTBTITLE,
Suffix = role.Person.Suffix.FTXTBSUFFIX
});
似乎多了很多可讀性也更快。
感謝您的建議,我一定會記住爲不同數量的參數進行多個編譯查詢!
正如我在加布裏埃爾通用汽車的回答中所說的那樣,我確實把它們放在了一個靜態的領域。我想,儘管如此,我仍然會嘗試110%。儘管如此,我將只能將部分放到編譯查詢中的where子句中嗎? – 2012-04-07 18:51:50
我添加了更多的東西。 – usr 2012-04-07 19:13:03
哦,關於基數事情的好主意!你是對的,大多數請求將少於10個角色id。絕對是要看的東西。謝謝! – 2012-04-07 19:27:34