EF下批量更新数据有没有更快的方法啊~

金虎大王 2019-06-12 12:14:01
最近用ABP框架做项目,其封装了EF来实现其仓储,遇到需要批量写入数据的业务,但是貌似没有发现批量更新(Update)的方法,只能做一个循环来更新数据。
做了一个2000条的更新测试,耗时竟然高达24秒。。将测试放到10000条竟然耗时超过10分钟,到底是EF性能降低,或者是ABP框架的问题,还是我的姿势不对,求大佬解惑。另求科学的批量更新数据库的方法!
另外,Insert 10000条耗时1.4秒。。
数据库为SQL Server2012


...全文
3853 40 打赏 收藏 转发到动态 举报
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
金虎大王 2019-06-14
  • 打赏
  • 举报
回复
引用 38 楼 加油馒头 的回复:
[quote=引用 31 楼 足球中国 的回复:]
[quote=引用 30 楼 金虎大王 的回复:]
[quote=引用 29 楼 足球中国 的回复:]
居然生产环境下用EF。。。

不用EF的话,生产环境下推荐一下?[/quote]
我们有自己的SQL生成工具。可以生成更新某几个字段,某几个表,生成事务代码,生成关联查询,生成多层继承MODEL。生成WCF,WEBSERVICE接口,生成验证框架,日志代码,生包含统一的验证框架和简单的验证代码,生成简单的界面。整个生成过程可以保存为项目。下次打开还可以修改model增加字段,更新增加字段等。对分库,分表暂时处理比较简单。[/quote]

类似动软生成器?[/quote]

估计说的就是代码生成器。。好像讨论不搭边
polllkk 2019-06-13
  • 打赏
  • 举报
回复
季秋二十九! 2019-06-13
  • 打赏
  • 举报
回复
NBNB佩服呀
zhzhsh0412130128 2019-06-13
  • 打赏
  • 举报
回复
很有用的帖子
左耳边的期盼 2019-06-13
  • 打赏
  • 举报
回复
我只是打酱油的
金虎大王 2019-06-13
  • 打赏
  • 举报
回复
引用 31 楼 足球中国 的回复:
[quote=引用 30 楼 金虎大王 的回复:]
[quote=引用 29 楼 足球中国 的回复:]
居然生产环境下用EF。。。

不用EF的话,生产环境下推荐一下?[/quote]
我们有自己的SQL生成工具。可以生成更新某几个字段,某几个表,生成事务代码,生成关联查询,生成多层继承MODEL。生成WCF,WEBSERVICE接口,生成验证框架,日志代码,生包含统一的验证框架和简单的验证代码,生成简单的界面。整个生成过程可以保存为项目。下次打开还可以修改model增加字段,更新增加字段等。对分库,分表暂时处理比较简单。[/quote]

本质还是ado?
足球中国 2019-06-13
  • 打赏
  • 举报
回复
引用 30 楼 金虎大王 的回复:
[quote=引用 29 楼 足球中国 的回复:] 居然生产环境下用EF。。。
不用EF的话,生产环境下推荐一下?[/quote] 我们有自己的SQL生成工具。可以生成更新某几个字段,某几个表,生成事务代码,生成关联查询,生成多层继承MODEL。生成WCF,WEBSERVICE接口,生成验证框架,日志代码,生包含统一的验证框架和简单的验证代码,生成简单的界面。整个生成过程可以保存为项目。下次打开还可以修改model增加字段,更新增加字段等。对分库,分表暂时处理比较简单。
金虎大王 2019-06-13
  • 打赏
  • 举报
回复
引用 29 楼 足球中国 的回复:
居然生产环境下用EF。。。

不用EF的话,生产环境下推荐一下?
足球中国 2019-06-13
  • 打赏
  • 举报
回复
居然生产环境下用EF。。。
加油馒头 2019-06-13
  • 打赏
  • 举报
回复
引用 31 楼 足球中国 的回复:
[quote=引用 30 楼 金虎大王 的回复:] [quote=引用 29 楼 足球中国 的回复:] 居然生产环境下用EF。。。
不用EF的话,生产环境下推荐一下?[/quote] 我们有自己的SQL生成工具。可以生成更新某几个字段,某几个表,生成事务代码,生成关联查询,生成多层继承MODEL。生成WCF,WEBSERVICE接口,生成验证框架,日志代码,生包含统一的验证框架和简单的验证代码,生成简单的界面。整个生成过程可以保存为项目。下次打开还可以修改model增加字段,更新增加字段等。对分库,分表暂时处理比较简单。[/quote] 类似动软生成器?
狮子TABA 2019-06-13
  • 打赏
  • 举报
回复
好厉害的样子,还有更详细的的解释吗
shiiki 2019-06-13
  • 打赏
  • 举报
回复
等高手出现!!!!
正怒月神 2019-06-12
  • 打赏
  • 举报
回复
如果可以使用sqlbulkcopy,那我感觉扩展继承自EfRepositoryBase的仓储类, 速度可能会更快。但是我没有测试过。 不过当中model转datatable的话,不清楚会不会慢。
正怒月神 2019-06-12
  • 打赏
  • 举报
回复
好像并没什么办法。但是你能不能扩展方法,使用sqlbulkcopy,这个我没测试过。 我测试了一下 ef的实体更新,ef通过扩展sql更新,和ado.net 更新 展示出来的ado.net最快,其次 是 ef的sql,最后是实体。
static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();

            Entities db = new Entities();
            //抓取数据
            var q = db.Movies.ToList();
            Console.WriteLine("EF 通过对象更新=》");
            Console.WriteLine("数据总数"+q.Count);
            //数据赋值
            for (int i = 0; i < q.Count; i++)
            {
                q[i].Title = i.ToString();
                q[i].ReleaseDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                q[i].Genre = i.ToString();
                q[i].Price = 10 * i;
                q[i].ImageType = 1;
            }
            //更新
            sw.Start();
            db.SaveChanges();
            sw.Stop();
            Console.WriteLine("更新数据:" + sw.ElapsedMilliseconds);
            Console.WriteLine("==========================================");

            Console.WriteLine("EF 通过sql更新=》");
            //更新
            sw.Reset();
            sw.Restart();
            string sql = "update Movies set Title=@title,ReleaseDate=@releaseDate,Genre=@genre,Price=@price,ImageType=imageType where ID=@id";
            for (int i = 0; i < q.Count; i++)
            {

                SqlParameter[] sp = new SqlParameter[6]{
                    new SqlParameter("title",q[i].Title),
                    new SqlParameter("releaseDate",q[i].ReleaseDate),
                    new SqlParameter("genre",q[i].Genre),
                    new SqlParameter("price",q[i].Price),
                    new SqlParameter("imageType",q[i].ImageType),
                    new SqlParameter("id",q[i].ID),
                };
                db.Database.ExecuteSqlCommand(sql, sp);
            }
            sw.Stop();
            Console.WriteLine("更新数据:" + sw.ElapsedMilliseconds);
            Console.WriteLine("==========================================");
            Console.WriteLine("sql更新=》");
            //更新
            sw.Reset();
            sw.Restart();
            SqlConnection con = new SqlConnection(ConnectionString);
            con.Open();
            for (int i = 0; i < q.Count; i++)
            {
                
                SqlParameter[] sp=new SqlParameter[6]{
                    new SqlParameter("title",q[i].Title),
                    new SqlParameter("releaseDate",q[i].ReleaseDate),
                    new SqlParameter("genre",q[i].Genre),
                    new SqlParameter("price",q[i].Price),
                    new SqlParameter("imageType",q[i].ImageType),
                    new SqlParameter("id",q[i].ID),
                };

                SqlCommand cmd = new SqlCommand(sql, con);
                cmd.Parameters.AddRange(sp);
                cmd.ExecuteNonQuery();
            }
            con.Close();
            sw.Stop();
            Console.WriteLine("更新数据:" + sw.ElapsedMilliseconds);

            Console.ReadKey();
        }
datafansbj 2019-06-12
  • 打赏
  • 举报
回复
据我的经验,EF的效率确实不敢恭维,如果是简单的业务逻辑、小众的数据量还可以使用,一旦涉及大数据量、复杂的表关联,其效率是很低的。
一个武术猴子 2019-06-12
  • 打赏
  • 举报
回复
这个 ef实现数据的写入,和批量的更新确实,有很多的问题,这个技术选型的时候应该考虑,因为ef 这个进行数据库的操作需要进行2次的编译,打个比方,一个sql语句执行需要0.001秒,ef执行的数据的添加,就需要在 sqlserver中进行2次编译,需要0.002秒,EF性能确实相对于ado 更慢,如果 做数据的显示和开发的话,速度都比较快,因为都是对象了,解决方法:这块选用ado处理吧,,,有问题的地方希望大家多多指教,
kingqueenno1 2019-06-12
  • 打赏
  • 举报
回复
差不多吧,我觉得楼主说的其实还可以
金虎大王 2019-06-12
  • 打赏
  • 举报
回复
感谢各位有启发的回答,我把分散一散
金虎大王 2019-06-12
  • 打赏
  • 举报
回复
引用 9 楼 娃都会打酱油了 的回复:
更新数据就是对读取出来的数据实体,遍历修改数据后,全部做完后,最后再做save操作,这样就是一次提交


感谢版主,此贴完结。
最后换了一种方式,感谢版主提醒 操作更新的本质,就使用仓储方法读出实体,在实体中循环更新实体的值,最终方法结束后就会save,这样的速度就相当快了~
测试10000条更新数据耗时1.29秒。符合业务需求


上测试代码

public async Task<string> Update(bool input)
{
List<Test> tabale= GetData();
var Start = DateTime.Now;
var query = await _entityTest.GetAllListAsync();//查出实体
int i = 0;
if (input)
{
//*直接再调用Update的仓储方法
//foreach (var t in Tests)
//{
// await _entityTest.UpdateAsync(t);
//}


//*给使用了仓储查询的实体进行更新
foreach(var t in tabale)
{
var result = query.FirstOrDefault(a => a.Id == t.Id);
result.Title = t.Title;
result.CreationTime = t.CreationTime;
result.CreatorUserId = t.CreatorUserId;
result.DeleterUserId = t.DeleterUserId;
result.DeletionTime = t.DeletionTime;
result.IsDeleted = t.IsDeleted;
result.LastModificationTime = t.LastModificationTime;
result.LastModifierUserId = t.LastModifierUserId;
result.TenantId = t.TenantId;
}
}
var End = DateTime.Now;
Console.WriteLine("更新10000条数据,耗时:"+(End - Start).ToString());
return (End - Start).ToString();
}

private List<Test> GetData()
{
List<Test> t = new List<Test>();
for (int i = 0; i < 10000; i++)
{
var temp = new Test();
temp.Id = i+3;
temp.Title = "测试!";
temp.CreatorUserId = 2;
temp.DeleterUserId = 1;
temp.DeletionTime = DateTime.Now;
temp.CreationTime = DateTime.Now;
temp.IsDeleted = false;
temp.LastModificationTime = DateTime.Now;
temp.LastModifierUserId = 2;
temp.TenantId = 3;
t.Add(temp);
}
return t;
}



irontigerhh 2019-06-12
  • 打赏
  • 举报
回复
看看!!!!!!!!!!!!
加载更多回复(20)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧