Оптимизировать запись в бд. Entity Framework

381
28 декабря 2016, 02:06

Есть база SQLite, с таблицами - Messages и Users. Содержит примерно 100 000 пользователей.

Нужно добавлять / обновлять сообщения, и пользователей, которые сделали репосты. На каждые 100 сообщений приходится ~6000 репостнувших пользователей. Сейчас на добавление 1 сообщения (в котором ~300 репостов), если всех репостнувших пользователей еще нет в базе, уходит ~14 секунд (это нормально?).

Делаю так:

using (AppDbContext db = new AppDbContext())
{
    // Получаем всех пользователей, чтобы сравнивать с репостнувшими пользователями
    usersFromDb = db.Users.ToList();
    /*****
     Т.к. пользователей в базе много, получение всех пользователей не оптимально.
     Но лучше ли будет делать много запросов (для каждого пользователя), вместо этого одного?
    *****/
}
using (AppDbContext db = new AppDbContext())
{
    foreach (var message in messages)
    {
        if (message.RepostUsers != null)
        {
            // Проходим по списку репостнувших пользователей
            /*****
             Эта часть занимает много времени
             Можно ли оптимизировать?
            *****/
            foreach (var user in message.RepostUsers)
            {
                // Ищем по пользователям из базы
                var dbUser = usersFromDb.Find(u => u.Id == user.Id);
                if (dbUser == null)
                {
                    // Если не нашли, помечаем новым
                    db.Entry(user).State = EntityState.Added;
                }
                else if (dbUser.Name != user.Name)
                {
                    // Если нашли и есть изменения, помечаем измененным
                    db.Entry(user).State = EntityState.Modified;
                }
                else
                {
                    // Если нашли и изменений нет, помечаем не измененным
                    db.Entry(user).State = EntityState.Unchanged;
                }
            }
        }
        // Получаем Message из базы
        var dbMessage = db.Messages.AsNoTracking().FirstOrDefault(p => p.Id == message.Id);
        // Message всегда либо новое, либо измененное. Помечаем
        db.Entry(message).State = dbMessage != null ? EntityState.Modified : EntityState.Added;
    }
    db.Messages.AddRange(messages);
    db.SaveChanges();
}

Вопрос 1.
Т.к. пользователей в базе много, получение всех пользователей не оптимально. Но лучше ли будет делать много запросов (отдельно для каждого репостнувшего пользователя), вместо одного?

Вопрос 2.
Когда меняю у пользователей состояния через db.Entry(user).State, объекты помещаются в кэш для отслеживания изменений? Т.е. AsNoTracking не учитывается? Если так, нужно ли это изменить и как?

Answer 1

Отвечаю только на вопрос по оптимизации. Вы каждый раз перебираете usersFromDb в поисках Id. Для таких целей надо использовать словарь. Вот код:

Dictionary<int,User> usersFromDb;
...
usersFromDb = db.Users.ToDictionary(x=>x.Id, x=>x);
...
// Ищем по пользователям из базы
if (usersFromDb.ContainsKey(userId))
{
    var dbUser = usersFromDb[userId];
...

Словарь позволяет совершать поиск за постоянное время O(1). В то время как поиск по листу происходит за линейное время O(n).

Answer 2

Рассмотри вариант с PostgreSQL, потому что SQLite - реляционная БД. Не вдаюсь в подробности. С одной стороны просто, но чем больше записей в БД, тем тяжелее запросы. Увеличь число записей в два раза в своей БД и посмотришь, стоит ли работать дальше с ней.

READ ALSO
Перемещение формы за любую часть

Перемещение формы за любую часть

Как сделать так, чтобы перемещение формы осуществлялось не только за верхнюю границу, а за любую часть данной формы?

478
Как открыть форму если форма находиться в другой папке

Как открыть форму если форма находиться в другой папке

Форма и код который я пишу находиться в разных папках Код(в папке нет той формы который указываю):

412
C#.Анимация с формой

C#.Анимация с формой

Можно ли при нажатии на "Esc" переместить плавно форму в верхний левый угол рабочего экрана? Это как перетащить мышьюСпасибо

342
Как загрузить изображение в бд php

Как загрузить изображение в бд php

Не могу загрузить изображение в БДВыдает ошибку "Необходимо загрузить изображение", то есть он уже выдает ошибку в первом условии следующего...

346