Неэффективное «ЛЮБОЕ» предложение LINQ - PullRequest
2 голосов
/ 16 марта 2010

У меня есть запрос, который возвращает пользовательский «фид», который, по сути, является всей его деятельностью. Если пользователь вошел в систему, запрос будет отфильтрован, так что в ленту будут включены не только все данные указанного пользователя, но и любые его друзья.

Структура базы данных включает в себя таблицу действий, в которой содержится пользователь, создавший действие, и таблицу UserFriends, в которой содержатся любые пары друзей с использованием столбцов FrienderId и FriendeeId, которые сопоставляются с UserIds.

Я настроил свой запрос LINQ, и он прекрасно работает для получения нужных мне данных, однако я заметил, что запрос превращается в X количество предложений CASE в профилировщике, где X - это общее количество действий в базе данных. , Это, очевидно, будет ужасно, когда база данных будет иметь пользовательскую базу больше, чем я и 3 тестовых пользователя.

Вот SQL-запрос, который я пытаюсь выполнить:

select * from [Action] a 
where a.UserId = 'GUID'
OR a.UserId in 
    (SELECT FriendeeId from UserFriends uf where uf.FrienderId = 'GUID')
OR a.UserId in 
    (SELECT FrienderId from UserFriends uf where uf.FriendeeId = 'GUID')

Это то, что у меня сейчас есть в качестве LINQ-запроса.

feed = feed.Where(o => o.User.UserKey == user.UserKey 
      || db.Users.Any(u => u.UserFriends.Any(ufr => ufr.Friender.UserKey == 
                                             user.UserKey && ufr.isApproved)
      || db.Users.Any(u2 => u2.UserFriends.Any(ufr => ufr.Friendee.UserKey == 
                                                user.UserKey && ufr.isApproved)
      )));

Этот запрос создает это: http://pastebin.com/UQhT90wh

Это отображается X раз в трассировке профиля, по одному разу для каждого действия в таблице. Что я делаю неправильно? Есть ли способ убрать это?

1 Ответ

1 голос
/ 17 марта 2010

Я бы разделил запрос на два запроса,

  1. Найдите всех друзей для пользователя, выберите их пользовательские ключи и поместите их в список.
  2. Отфильтруйте ленту в соответствии с ключом пользователя и его ключами.

Вот мой снимок, не зная ваших точных поверхностей и объектов, но он показывает концепцию:

    var friends = db.UserFriends
                    .Where(x => x.isApproved && (
                                    x.Friender.UserKey == user.userKey || 
                                    x.Friendee == user.userKey
                                )
                    )
                    .Select(x => x.userKey)
                    .Distinct()
                    .ToList();
    feed = feed.Where(x => x.userKey == user.userKey || friends.Contains(x.UserKey));

Это должно привести к запросу, подобному этому

SELECT ... 
FROM feed 
WHERE userKey == 'userkey1' OR userKey in ('userKey2', 'userKey3', ...)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...