有一个 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();
}
问题
一 数据库中有很多用户,获取所有用户并不是最优的。但是提出许多请求(分别针对每个转发的用户)而不是一个更好吗?
问题 2:
当我通过 更改用户状态时db.Entry(user).State,是否会缓存对象以跟踪更改?那些。AsNoTracking没有考虑?如果是这样,是否应该更改以及如何更改?
我只回答优化问题。每次查找 Id 时,您都会遍历 usersFromDb。为此,您需要使用字典。这是代码:
该字典允许在恒定的 O(1) 时间内进行搜索。搜索工作表发生在线性时间 O(n) 内。
考虑 PostgreSQL,因为 SQLite 是一个关系数据库。我不细说。一方面简单,但是数据库中的记录越多,查询越重。将数据库中的记录数加倍,看看它是否仍然值得使用。
那么发生了什么:
有几个问题:
AddRange不起作用,因为AddRange设置记录的状态Addedwhere. 但这里的一切都不是那么简单 - 如果您添加 10 条消息,则进行选择会更快。如果每条消息有100条,那么用户很多,选择的时间比通过 获取所有记录的时间要长ToList()。db.Entry(user).State =,因为 这导致对内部算法DetectChanges的昂贵执行调用更正:
AddRangedb.Configuration.AutoDetectChangesEnabled = false;结果:
特别感谢@Ruslan Artamonov提供的提示和答案。