带有隧道到MySQL的EF(C#) - 优化数据库调用

时间:2015-07-26 01:56:42

标签: c# mysql entity-framework

所以我有程序来处理MySQL数据库中的某些工作。我通过SSH隧道连接与putty连接(是的,我知道在服务器上启动程序会好得多,但我在这里没有选择)。

程序速度有问题。我通过添加“.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中调用数据库。

1 个答案:

答案 0 :(得分:1)

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

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

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

如果要在应用程序中执行此操作,可以使用以下使用LINQ to Entities和LINQ扩展方法的代码。我假设您在player_data表中有achievements的外键,因此Entity Framework为您的player_data实体生成achievements懒惰属性:

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;
    }
}