录入实时位置信息需要插入大量数据,连续不断的,同时要能够读取出来。
添加数据的代码,这里要添加历史数据和修改实时数据,两种数据是放到两个数据库中的
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也是一条一条的加到数据库中,时间没变。
想安装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运行后,速度会快很多。