EF (c#)与隧道到MySQL -优化数据库调用

本文关键字:MySQL 优化 数据库 调用 隧道 EF | 更新日期: 2023-09-27 18:04:45

所以我有程序来处理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。如果这样的玩家不存在,删除他的成就。

这都是在做的,所以我不会因为一次加载所有的数据而使内存过载。

我知道问题是在每一步检查数据库,但我不知道如何做到这一点,没有它。我尝试的其他事情会产生错误,因为EF无法将其转换为SQL,或者在试图访问不存在的实体时抛出异常。

我将需要类似的事情更经常,所以我会非常感激,如果有人能帮助我使它,所以没有必要调用数据库在"foreach"。我知道我可以尝试加载整个players_data表,然后检查Any(),但有些表我需要它太大了。

哦,关闭跟踪更改在这一点上没有帮助,因为它不是减慢程序的原因。

我将感激任何帮助,提前感谢!

编辑:嗯,有没有一种方法来获得成就,没有player_data对应他们通过一个查询使用关联?比如在成就查询中添加如下内容:

where !data.player_data.Exists()

Intellisense告诉我,此时没有类似Exists或Any的东西可以使用。有类似的技巧吗?它肯定会处理我的速度问题,因为在foreach中不需要数据库调用。

EF (c#)与隧道到MySQL -优化数据库调用

如果你想删除没有相应用户记录的成就,那么你可以使用下面的SQL查询:

DELETE a
FROM `achievements` a
LEFT JOIN `user` AS u 
ON u.`playerID` = a.`playerID`
WHERE u.`playerID` IS NULL;

SQL查询将比实体框架快一个数量级。

如果你想在应用程序中做到这一点,你可以使用下面的代码,使用LINQ到实体和LINQ扩展方法。我假设您在achievements表中有player_data的外键,因此实体框架为您的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;
    }
}