我正在编写一段代码,由一位同事编写,它与我们公司使用的 CRM 应用程序交互。这段代码中有两个 LINQ to Entities 查询在我们的应用程序中多次执行,我被要求优化它们,因为其中一个非常慢。
这些是查询:
第一个查询,这个查询几乎可以立即编译。它从 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 Profiler 并从两个查询中获取 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
});
似乎更具可读性,而且速度也更快。
感谢您的建议,我一定会牢记对不同数量的参数进行多个编译查询的建议!