所以我有程序来处理 MySQL 数据库中的某种工作。我正在使用 Putty 通过 SSH 隧道连接(是的,我知道在服务器本身上启动程序会好得多,但我在这里别无选择)。
我在程序速度方面遇到了一些问题。我通过添加“.Include(table_name)”解决了一个问题,但我想不出一种方法来解决这个问题。
因此,此方法的目的是清除数据库中不需要的、损坏的记录。简化的代码如下所示:
using (var dbContext = new MyDatabase_dataEntities())
{
List<achievements> achiList = new List<achievements>();
var achievementsQuery = from data in dbContext.achievements
orderby data.playerID
select data;
achiList = achievementsQuery.Skip(counter * 5000).Take(5000).ToList();
foreach (achievements record in achiList)
{
var playerExists = from data in dbContext.players_data
where data.playerID == record.playerID
select data;
if(!playerExists.Any())
{
dbContext.achievements.Remove(record);
}
}
dbContext.SaveChanges();
counter++;
}
所以这是以这种方式构建的,因为我想加载成就表然后检查成就是否在 player_data 中有他们的玩家。如果这样的玩家不存在,则删除他的成就。
这一切都在做,所以我不会因为一次加载所有数据而使我的内存过载。
我知道问题在于在 foreach 步骤中检查数据库,但我无法弄清楚没有它该怎么做。我尝试的其他事情产生了错误,要么是因为 EF 无法将其转换为 SQL,要么是在尝试访问不存在的实体时抛出了异常。在 foreach 中执行此操作会导致整个程序出现瓶颈,这可能是因为对服务器执行 ping 操作。
我会更频繁地需要类似的东西,所以如果有人能帮助我制作它,我将非常感激,这样就不需要在“foreach”中调用数据库了。我知道我可以尝试加载整个 players_data 表,然后检查 Any(),但是我需要它的一些表太大了。
哦,关闭跟踪更改在这一点上没有帮助,因为它不会减慢程序速度。
如果有任何帮助,我将不胜感激,在此先感谢!
编辑:嗯,有没有一种方法可以通过使用关联的查询来获得没有与之对应的 player_data 的成就?比如添加到成就查询中:
where !data.player_data.Exists()
Intellisense 告诉我此时没有像 Exists 或 Any 这样的东西可以使用。有没有类似的技巧?它肯定会解决我在那里遇到的速度问题,因为不需要在 foreach 中调用数据库。
最佳答案
如果你想删除没有相应用户记录的成就,那么你可以使用下面的SQL查询:
DELETE a
FROM `achievements` a
LEFT JOIN `user` AS u
ON u.`playerID` = a.`playerID`
WHERE u.`playerID` IS NULL;
SQL 查询将比 Entity Framework 快一个数量级。
如果您想在应用程序中执行此操作,可以使用以下使用 LINQ to Entities 和 LINQ 扩展方法的代码。我假设您在 achievements
表中有一个 player_data
的外键,因此 Entity Framework 会为您的 achievements
生成 player_data
惰性属性实体:
using (var dbContext = new MyDatabase_dataEntities())
{
var proceed = true;
while (proceed)
{
// Get net 1000 entities to delete
var entitiesToDelete = dbContext.achievements
.Where(x => x.players_data == null)
.Take(1000)
.ToList();
dbContext.achievements.RemoveRange(entitiesToDelete);
dbContext.SaveChanges();
// Proceed if deleted entities during this iteration
proceed = entitiesToDelete.Count() > 0;
}
}
如果您更喜欢使用 LINQ 查询语法而不是扩展方法,那么您的代码将如下所示:
using (var dbContext = new MyDatabase_dataEntities())
{
var proceed = true;
while (proceed)
{
// Get net 1000 entities to delete
var query = from achievement in dbContext.achievements
where achievement.players_data == null
select achievement;
var entitiesToDelete = query.ToList();
dbContext.achievements.RemoveRange(entitiesToDelete);
dbContext.SaveChanges();
// Proceed if deleted entities during this iteration
proceed = entitiesToDelete.Count() > 0;
}
}
关于c# - 带隧道到 MySQL 的 EF (C#) - 优化数据库调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31632901/