Более эффективный Linq to SQL - PullRequest
       0

Более эффективный Linq to SQL

4 голосов
/ 07 февраля 2012

Я играл с Linq to SQL, чтобы помочь мне в поиске простой БД. База данных состоит из двух таблиц Player и Team, каждая запись игрока имеет Team Id для связи двух таблиц (Player.TeamId -> Team.Id).

Чтобы добавить немного сложности, таблица Team содержит исторические данные за последние 10 сезонов. Это означает, что каждая команда может иметь до 10 различных записей в таблица команды, относящаяся к представленным 10 сезонам.

Я хочу, чтобы мой запрос выполнял поиск игрока, который возвращает список игроков, соответствующих критериям поиска, и список товарищей по команде для каждого из возвращенных игроков этой команды в том сезоне.

Критерии поиска включают имя, фамилию, (список) сезонов и название команды.

Мой запрос выглядит так:

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);
}
}

Это работает и возвращает список игроков (playerList), которые соответствуют критериям поиска, и для каждого из этих игроков я могу сопоставить своих товарищей по команде из результатов второго запроса (teamMateList).

Моя проблема в том, что Linq to SQL переводит это в совершенно неэффективный SQL. Первая проблема заключается в том, что он выбирает всю таблицу Player из БД - я предполагаю, что это связано с тем, что Linq to SQL не может перевести мои предложения Where в стандартный SQL и поэтому возвращает всю таблицу и выполняет часть кода запроса в коде.

Вторая проблема заключается в том, что при выполнении второго запроса Linq to SQL генерирует отдельные запросы к БД для каждого члена playerList. При чтении кода это, вероятно, имеет смысл, но я бы подумал, что Linq был бы достаточно умен, чтобы перевести это в один запрос, что привело бы к более эффективному поиску.

Есть какие-нибудь мысли / предложения о том, как упростить мой запрос?

Ответы [ 2 ]

1 голос
/ 07 февраля 2012

Я предполагаю, что это связано с тем, что Linq to SQL не может перевести мои предложения Where в стандартный SQL, и поэтому возвращает всю таблицу и выполняет часть кода Where в коде?

Или, другими словами - потому что вы пишете условие, игнорирующее любой разумный подход, который LINQ мог бы перевести.

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

Если searchRequest.Surname имеет значение null, НЕ ВЫБИРАТЬ.

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

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

Никто не говорит, что вам нужно определять всю часть LINQ за один прогон. Это было ужасно при написании ручного SQL, иэто ужасно с LINQ. Выражение LINQ, где результат снова является IQueryable и цепочка, как это явно поддерживается. Мы делаем высокоэффективный LINQ для сотен миллионов строк, и это выглядит великолепно - но только потому, что мы не пишем код в этомплохо, как вы делаете.

Ваша вторая проблема та же - вы атакуете проблему с неправильной стороны, заставляя LINQ использовать неэффективношаблон поиска.Сделайте выбор с помощью группы, а затем присоедините сторону клиента к другой таблице.

0 голосов
/ 08 февраля 2012

LINQPad Может помочь вам с локальной отладкой ваших операторов LINQ.

Вы также можете использовать SQL Server Profiler при отладке LINQ to SQL Queries, он покажет вам не только то, во что .NET переводит запрос, но и все остальное, что выбрасывается в вашу БД. Это также очень полезно при попытке увеличить проблемы с производительностью с помощью LINQ Queries, переводящих смехотворно длинные эквивалентные SQL-запросы.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...