Asp.Net MVC + WCF (3) EF插入大量数据

录入实时位置信息需要插入大量数据,连续不断的,同时要能够读取出来。

添加数据的代码,这里要添加历史数据和修改实时数据,两种数据是放到两个数据库中的

public bool AddPosition(Position position)
        {
            if (position == null) return false;
            if (Position.Add(position))//添加历史数据
            {
                return EditTagPosition(position);//修改实时数据
            }
            else
            {
                ErrorMessage = Position.ErrorMessage;
                return false;
            }
        }


        public bool EditTagPosition(Position position)
        {
            TagPosition tagPos = TagPositions.FindByCode(position.Tag);//判断是否存在实时数据
            if (tagPos == null)
            {
                TagPosition tagPosition = new TagPosition(position);
                if (TagPositions.Add(tagPosition))//添加新的实时数据
                {
                    return true;
                }
                else
                {
                    ErrorMessage = Position.ErrorMessage;
                    return false;
                }
            }
            else
            {
                tagPos.Edit(position);
                if (TagPositions.Edit(tagPos))//修改实时数据
                {
                    return true;
                }
                else
                {
                    ErrorMessage = Position.ErrorMessage;
                    return false;
                }
            }
        }

这里的每个Edit、Add里面都有SaveChanged

循环300次,结果是用时9s,9000ms,一次相当于30ms,一次感觉还没关系,300次就完全不能接受了。

如果不修改实时数据,则300次,用时5s,提高了4s,也就是写入实时数据部分用时4s。

换一个角度,只修改实时数据,不加入到历史表中,用时4.5s。

改成,所有数据修改好后,执行SaveChanged

public bool AddPositions(List<Position> positions)
        {
            bool r = true;
            for (int i = 0; i < positions.Count; i++)
            {
                Position position = positions[i];
                if (AddPositionEx(position) == false)
                {
                    r = false;
                    break;
                }
            }
            Position.Save(); //统一插入历史数据            
            TagPositions.Save();
            return r;
        }

        public bool AddPositionEx(Position position)
        {
            bool r = false;
            if (position == null)
            {
                r = false;
            }
            if (Position.Add(position, false)) //添加历史数据,false:不保存           
            {
                r = EditTagPositionEx(position); //修改实时数据                
                //return true;            
            }
            else
            {
                ErrorMessage = Position.ErrorMessage;
                r = false;
            }
            //return EditTagPosition(position);
            //修改实时数据          
            return r;
        }

        public bool EditTagPositionEx(Position position)
        {
            TagPosition tagPos = TagPositions.FindByCode(position.Tag); //判断是否存在实时数据            
            if (tagPos == null)
            {
                TagPosition tagPosition = new TagPosition(position);
                if (TagPositions.Add(tagPosition))
                    //添加新的实时数据,保存,不然后面修改会出问题。              
                {
                    return true;
                }
                else
                {
                    ErrorMessage = Position.ErrorMessage;
                    return false;
                }
            }
            else
            {
                tagPos.Edit(position);
                if (TagPositions.Edit(tagPos, false)) //修改实时数据,false:不保存            
                {
                    return true;
                }
                else
                {
                    ErrorMessage = Position.ErrorMessage;
                    return false;
                }
            }
        }

用时5s,快了一些,应该时快在修改实时数据部分,其实只有最后一次提交给了数据库,而不像之前,每次都提交给数据库。

而这里的历史数据的Save()还是一条一条的插入数据的,就算我Add很多条后,Save也是一条一条的加到数据库中,时间没变。

参考:EF实现大批量数据库插入操作

想安装Z.EntityFramework.Extensions,结果安装失败,提示

Failed to initialize the Powershell host. If your powershell execution policy setting is set to AllSigned, open the package manager console to initialize the host first

搜索解决方案:Failed to initialize the PowerShell host 解决方案

按它的操作结果出问题:

Windows PowerShell updated your execution policy successfully, but the setting is overridden by a policy defined at a more specific scope. Due to the override, your shell will retain its current effective execution policy of RemoteSigned. Type "Get-ExecutionPolicy -List" to view your execution policy settings. For more information please see "Get-Help Set-ExecutionPolicy".

继续搜索解决方案:https://stackoverflow.com/questions/31559268/nuget-crash-in-visual-studio-2015

使用最后面的卸载重新安装NuGet的方式。

然后安装Z.EntityFramework.Extensions,成功了。

尝试用:

public bool AddPositions(List<Position> positions)
        {
            Db.BulkInsert(positions);
            Db.BulkSaveChanges();

结果出问题:

其他信息: Oops! We could not find the entityType 'Position'. Please report the issue to our support team: info@zzzprojects.com

考虑是不是要把Position的类型和BulkInsert代码放到一个dll中,不行。

试了EntityFramework.Extended,发现只支持批量更新和删除,批量添加没看到。

再试试其他的,发现好多第三方库提供或者声明提工批量插入功能,为什么官方不直接做进去呢,原理上不难才对。

想起来了,我的Positon时放到历史数据库中的,Db是实时数据库,还不一样。

改成

DbHistory.BulkInsert(positions);
            DbHistory.SaveChanges();

可以了。

速度快很多了,数据也有插入,第一次的时间快了一倍,但是从第二次开始,时间快了10被,应该是第一次做了些初始工作。

-------------------------------------------------------------------------------------------------------------------------

批量添加历史数据优化好了,这个是一个位置信息的情况,模拟数据代码:

        private void BtnTestInsertData_OnClick(object sender, RoutedEventArgs e)
        {
            Stopwatch watch=new Stopwatch();
            watch.Start();

            List<Position> positions = new List<Position>();
            for (int i = 0; i < 300; i++)
            {
                Position pos = new Position() {Tag = "00002",Time = DateTime.Now.Ticks,X=i,Y=0,Z=0, Flag = DateTime.Now.ToString() };
                positions.Add(pos);
            }
            positionBll.AddPositions(positions);

            watch.Stop();
            WriteLine(TbResult2,"用时:"+ watch.Elapsed+"\n");
        }
整理的Tag都是00002。

多个位置信息的情况下,修改实时数据部分就成了瓶颈,模拟数据代码

        public bool AddPositions(List<Position> positions)
        {
            bool r = true;
            //批量插入历史数据数据
            DbHistory.BulkInsert(positions);
            DbHistory.BulkSaveChanges();

            //修改实时数据 todo:处理大数据量修改问题
            for (int i = 0; i < positions.Count; i++)
            {
                Position position = positions[i];
                if (EditTagPositionEx(position) == false)
                {
                    r = false;
                    break;
                }
            }
            TagPositions.Save();
            return r;
        }

实际项目中定位卡的数量不会超过300张

用实时数据也用批量修改的方式

另外,在连接定位引擎时就把实时数据表检查一遍,这样实时数据修改时不用判断是用添加还是修改。

        /// <summary>
        /// 根据标签信息初始化实时位置信息表,这样跟定位引擎对接时就不用每次都判断是否是新增还是修改了
        /// </summary>
        public List<Tag> InitTagPosition(int mockPowerCount)
        {
            List<Tag> tags=Tags.ToList();

            var mockTags = GetMockTags(mockPowerCount, tags); //生成模拟数据,测试大数据量,mockPowerCount = 100的话,2个变成200个
            tags.AddRange(mockTags);
            List<TagPosition> tagPosList = TagPositions.ToList();//事先取出全部到内存中,比每次都到数据库中查询快很多。 100个从6.4s->1.8s,1.8s中主要是第一次查询的一些初始工作
            List<TagPosition> newPosList = new List<TagPosition>();

            foreach (Tag tag in tags)
            {
                //TagPosition tagPos = TagPositions.FindByCode(tag.Code);//100个要2s
                TagPosition tagPos = tagPosList.Find(i=>i.Tag==tag.Code);//判断是否存在实时数据
                if (tagPos == null)
                {
                    TagPosition tagPosition = new TagPosition(tag.Code);
                    newPosList.Add(tagPosition);
                }
            }

            TagPositions.Db.BulkInsert(newPosList);//插件Z.EntityFramework.Extensions功能
            TagPositions.Db.BulkSaveChanges();

            return tags;
        }

插入数据改为

        public bool AddPositions(List<Position> positions)
        {
            bool r = true;
            //批量插入历史数据数据
            DbHistory.BulkInsert(positions);//插件Z.EntityFramework.Extensions功能
            DbHistory.BulkSaveChanges();
            //获取并修改列表
            List<TagPosition> tagPosList = EditTagPositionList(positions);
            //3.更新列表
            TagPositions.Db.BulkUpdate(tagPosList);//插件Z.EntityFramework.Extensions功能
            TagPositions.Db.BulkSaveChanges();
            return r;
        }

        private List<TagPosition> EditTagPositionList(List<Position> positions)
        {
            //1.获取列表
            List<TagPosition> tagPosList = TagPositions.ToList(true);
            //2.修改数据
            for (int i = 0; i < positions.Count; i++)
            {
                Position position = positions[i];
                TagPosition tagPos = tagPosList.Find(item => item.Tag == position.Tag);
                tagPos.Edit(position);
            }
            return tagPosList;
        }

另外写了个异步的,这样就不会卡住了。

        public async Task AddPositionsAsyc(List<Position> positions)
        {
            //批量插入历史数据数据
            await DbHistory.BulkInsertAsync(positions);//插件Z.EntityFramework.Extensions功能
            await DbHistory.BulkSaveChangesAsync();

            //获取并修改列表
            List<TagPosition> tagPosList = EditTagPositionList(positions);
            //更新列表
            await TagPositions.Db.BulkUpdateAsync(tagPosList);//插件Z.EntityFramework.Extensions功能
            await TagPositions.Db.BulkSaveChangesAsync();
        }

最后,在用VS调试时发现,运行越久,相同数量的写入时间越慢,不知道什么原因。一旦一次写入的实际太慢,会导致定位信息不断积累起来。但是用exe运行后,速度会快很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值