简体   繁体   English

更高效的Linq to SQL

[英]More efficient Linq to SQL

I've been playing around with Linq to SQL to help me search a simple DB. 我一直在玩Linq to SQL来帮助我搜索一个简单的数据库。 The DB consists of two tables, Player and Team, with each player record having a Team Id to link the two tables(Player.TeamId -> Team.Id). 数据库由两个表组成,即Player和Team,每个玩家记录都有一个Team Id来链接两个表(Player.TeamId - > Team.Id)。

To add a little complexity the Team table contains historical data for the past 10 seasons. 为了增加一点复杂性,Team表包含过去10个赛季的历史数据。 This means that each team may have up to 10 different records in the team table, relating to the 10 seasons represented. 这意味着每个团队在团队表中最多可以有10个不同的记录,与所代表的10个季节相关。

What I want my query to do is search for a Player which returns a list of players matching the search criteria and a list of team-mates for each of the returned players for that team, that season. 我希望我的查询要做的是搜索一个播放器,该播放器返回符合搜索条件的玩家列表,以及该团队每个返回玩家的队友列表。

The search criteria includes Forname, Surname, (List of)Seasons and Team Name. 搜索条件包括Forname,Surname,(列表)季节和团队名称。

My query looks like this: 我的查询如下所示:

using (var context = DataContextFactory.Context)
{
var playerList = context.GetTable<Player>(t =>  searchRequest.Seasons.Contains((int) t.Team.Season))
                              .Where(p => string.Equals(p.Surname, (searchRequest.Surname ?? p.Surname), StringComparison.OrdinalIgnoreCase) &&
                                          string.Equals(p.Forename, (searchRequest.Forename ?? p.Forename), StringComparison.OrdinalIgnoreCase) &&
                                          string.Equals(p.Team.Name, (searchRequest.TeamName ?? p.Team.Name), StringComparison.OrdinalIgnoreCase)
                                    )).ToList();

var teamMateList = new List<Player>();

foreach (var Player in playerList.Select(p => context.GetTable<Player>(
                              tm => tm.Team.Id == p.Team.Id && tm.Id.CompareTo(p.Id) != 0)))
{
    otherPeopleList.AddRange(people);
}
}

This works and will return a list of players(playerList) who match the search criteria and for each of those players I can map their team mates from the second query results(teamMateList). 这将起作用并将返回与搜索条件匹配的玩家列表(playerList),并且对于每个玩家我可以从第二个查询结果(teamMateList)映射他们的队友。

My problem is that Linq to SQL translates this into quite inefficient SQL. 我的问题是Linq to SQL将其转换为非常低效的SQL。 The first issue is that it selects out the entire Player table from the DB - I assume this is because Linq to SQL can't translate my Where clauses to standard SQL and so returns the entire table and does the Where part of the query in code? 第一个问题是它从数据库中选择了整个Player表 - 我认为这是因为Linq to SQL无法将我的Where子句转换为标准SQL,因此返回整个表并在代码中执行查询的Where部分?

The second problem is that when doing the second query Linq to SQL generates seperate queries to the DB for each member of the playerList. 第二个问题是,在执行第二个查询时,Linq to SQL会为playerList的每个成员生成对DB的单独查询。 When reading the code this probably makes sense but I would have thought Linq would have been clever enough to translate this into a single query resulting in more efficient searching. 在阅读代码时,这可能是有道理的,但我认为Linq会非常聪明地将其转换为单个查询,从而提高搜索效率。

Any thoughts/suggestions on how to streamline my query? 有关如何简化查询的任何想法/建议?

I assume this is because Linq to SQL can't translate my Where clauses to standard SQL and so returns the entire table and does the Where part of the query in code? 我假设这是因为Linq to SQL无法将我的Where子句转换为标准SQL,因此返回整个表并在代码中执行查询的Where部分?

Or, in other words - because you write the condition ignoring any sensible approach that LINQ could translate. 或者,换句话说 - 因为你写的条件忽略了LINQ可以翻译的任何明智的方法。

string.Equals(p.Surname, (searchRequest.Surname ?? p.Surname string.Equals(p.Surname,(searchRequest.Surname ?? p.Surname

If searchRequest.Surname is null, then DO NOT SELECT. 如果searchRequest.Surname为null,则不要选择。

var query = context.GetTable<Player>(*first condition);

if (!string.IsNullOrEmpty(searchRequest.Surname) {
query = query.Where (x=> x.surname.StartsWIth (searchRequest.Surname);
}

No one says you have to define the whole LINQ part in one run. 没有人说你必须在一次运行中定义整个LINQ部分。 This was terrible when writing manual SQL, and it is terrible with LINQ. 在编写手动SQL时这很糟糕,LINQ很糟糕。 A LINQ expression where the result is an IQueryable again and chaining like this is explicitly supported. 显式支持LINQ表达式,其中结果再次为IQueryable并且链接为此类链接。 We do high efficient LINQ over hundreds of millions rows and it looks great - but only because we do not write the code in that bad a way you do. 我们在数亿行上做了高效的LINQ,它看起来很棒 - 但这只是因为我们不会以那么糟糕的方式编写代码。

Your second issue is the same - you attack the problem from the wrong side by forcing LINQ to use an inefficient search pattern. 您的第二个问题是相同的 - 您通过强制 LINQ使用低效的搜索模式从错误的方面解决问题。 Make a select with a group by and then join client side with the other table. 使用group by进行选择,然后将客户端与另一个表连接。

LINQPad Can help you with debugging your LINQ Statements locally. LINQPad可以帮助您在本地调试LINQ语句。

You can also use SQL Server Profiler when debugging LINQ to SQL Queries, it will not only show you what .NET is translating the query into but everything else being thrown at your DB. 您还可以在调试LINQ to SQL查询时使用SQL Server Profiler ,它不仅会向您显示.NET正在将查询转换为什么,而且还会向您显示在数据库中抛出的所有其他内容。 This is also very useful when trying to increase performance issues with LINQ Queries translating ridiculously long equivalent SQL Queries. 当尝试使用LINQ查询来翻译可笑的长等效SQL查询时,这也非常有用。

Hope this helps. 希望这可以帮助。

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

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