从 .net c# 应用程序循环正确有效地更新 sql 服务器数据库 table 中的数百条记录

Properly and efficiently update hundreds of records in sql server db table from .net c# application loop

我已经使用 Entity Framework 6 一段时间了,通常我一次更新 1 条记录。

但是,我需要遍历所有用户,300 - 1,000 个用户

更新数据库中的几个列会不会非常低效和缓慢?与 EF6.x ?我应该改用 ADO.NET 还是通过网络发送某种对象,一些批量更新??

目前我是这样更新的

rpmuser.usr_id = user;
rpmuser = db.rpm_usr.Find(rpmuser.usr_id);
rpmuser.lst_pwd_chg_dtm = dateTime;
rpmuser.cre_dtm = dateTime;

rpmuser.usr_pwd = hash;
rpmuser.salt = salt;

db.SaveChanges();

所以基本上如果我绕过其他用户就可以了吗?我还能如何通过批量更新来做到这一点?

for( ....  ) {
  // different user id 
  // all the other needed poco model changes above... etc.
  // db.SaveChanges()
}

您可以使用以下代码进行测试:

static void Main(string[] args)
{
    CreateAndSeedTheDatabase(); // Step 1: run this
    //UpdateAllOfTheProducts(); // Step 2: Comment out the above line and uncomment and run this line
}

static void CreateAndSeedTheDatabase()
{
    Context context = new Context();
    context.Database.Initialize(true);

    Product product;
    for (int i = 0; i < 1000; i++)
    {
        product = new Product() { ProductId = i, Name = "Product" + i };
        context.Products.Add(product);
    }
    context.SaveChanges();
}

static void UpdateAllOfTheProducts()
{
    Context context = new Context();
    Product[] products = context.Products.ToArray();
    foreach (Product product in products)
    {
        product.Name = product.ProductId + "Product";
    }
    context.SaveChanges();
}

public class Context : DbContext
{
    public Context()
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
    }
    public DbSet<Product> Products { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}

}

要正确有效地更新数百条记录,您需要尽可能减少数据库往返。

在你的例子中,你有两种方法进行繁重的数据库往返

查找方法

对于您需要更新的每个用户,您都在进行一次数据库往返。有多种方法可以快速减少这种情况。

  • 加载所有用户并使用带有键 "usr_id" 的字典只进行一次数据库往返(如果数据库不包含数百万用户,效果很好!)

  • 创建包含所有 "usr_id" 的列表并使用包含方法

  • 一次检索所有用户

示例:

// Work well if the database doesn't contain to much users
var userDict = db.rpm_usr.ToList().ToDictionary(x => x.usr_id);


// Be careful, the list cannot contains more than 2099 items (SQL Parameters limit = 2100)
var userDict = db.rpm_usr.Where(x => ids.Contains(x.usr_id)).ToDictionary(x => x.usr_id);

两种解决方案都只进行一次数据库往返,可以非常高效地从字典中检索用户。

保存更改方法

SaveChanges 方法为每条要更新的记录执行数据库往返。因此,如果您更新 1000 个用户,将进行 1000 次数据库往返,这非常慢。

免责声明:我是项目的所有者Entity Framework Extensions

此项目允许执行 BulkSaveChanges 和 BulkUpdate 以显着提高性能:

for( ....  ) {
  // different user id 
  // all the other needed poco model changes above... etc.
  db.BulkSaveChanges()
}

for( ....  ) {
  // different user id 
  // all the other needed poco model changes above... etc.
  db.BulkUpdate(users)
}