我正在使用Entity Framework和Linq。我需要对我的对象的2个属性进行查询。
我在数据库上有这个对象(大约200.000条记录):
public class DeviceState
{
public int ID { get; set; }
public DateTime TimeStamp { get; set; }
public string StatusCode { get; set; }
public int Device_ID { get; set; }
}
我需要这样做一个查询:
List<DeviceState> listState = systemDB.DeviceStates.Where(s => s.Device_ID == DeviceID).Where(l => l.TimeStamp > startDate).Where(l => l.TimeStamp < endDate).Where(s => s.StatusCode == "xx").ToList();
foreach (DeviceState status in listState)
{
// here I need to save in an object the status code and the time stamp:
object.StatusCode= status.StatusCode;
object.TimeStamp = status.TimeStamp;
}
此查询需要很长时间(约15分钟)。我认为这是由于列表的创建。所以我尝试了这个:
foreach (DeviceState status in systemDB.DeviceStates.Where(s => s.Device_ID == DeviceID).Where(l => l.TimeStamp > startDate).Where(l => l.TimeStamp < endDate).Where(s => s.StatusCode == "xx"))
{
// here I need to save in an object the status code and the time stamp:
object.StatusCode= status.StatusCode;
object.TimeStamp = status.TimeStamp;
}
创建列表的速度要快得多。但由于foreach循环,我仍然存在性能问题。每个元素需要5毫秒。
我需要找到一个需要几秒钟才能执行的解决方案。
答案 0 :(得分:3)
您可以执行这些操作来帮助生成查询。
StatusCode
&#34; xx&#34;所以也不需要检索它。这样可以减少通过网络返回的数据,减少将数据映射到对象所需的周期,以及减少数据占用的内存。代码
// list of timestamps from database
var timeStamps = systemDB.DeviceStates.Where(s => s.Device_ID == DeviceID &&
s.TimeStamp > startDate &&
s.TimeStamp < endDate &&
s.StatusCode == "xx")
.Select(x => x.TimeStamp).ToList();
如果你仍然想要你的状态代码,因为你删除了过滤器,你就可以这样做
var timeStamps = systemDB.DeviceStates.Where(s => s.Device_ID == DeviceID &&
s.TimeStamp > startDate &&
s.TimeStamp < endDate &&
s.StatusCode == "xx")
.Select(x => new {x.TimeStamp, x.StatusCode})
.ToList();
答案 1 :(得分:1)
你可以在子句
中做一个瘦身List<DeviceState> listState = systemDB.DeviceStates.Where(
l => l.Device_ID == DeviceID
&& l.TimeStamp > startDate
&& l.TimeStamp < endDate
&& l.StatusCode == "xx"
).ToList();
然后使用for
而不是foreach
,因为foreach
在大量数据的情况下会更慢
for (int i = 0; i< listState.Count; i++ )
{
object.StatusCode= listState[i].StatusCode;
object.TimeStamp = listState[i].TimeStamp;
}
答案 2 :(得分:1)
Igor的回答已经显示了在任何情况下你应该做的最明显的改进。
现在,如果您手动处理大量数据,那么您可能希望在与System.Threading.Tasks.Parallel.ForEach并行的多个线程中执行此操作。代码(有其他改进):
var deviceStateTime = systemDB.DeviceStates.Where(s => s.Device_ID == DeviceID
&& s.TimeStamp > startDate)
&& s.TimeStamp < endDate
&& s.StatusCode == "xx");
Parallel.ForEach(deviceStateTime, (time) =>
{
object.StatusCode = "xx";
object.Timestamp = time;
});
请注意,我没有测试它(我是从记忆中写下来的),所以我可能在某个地方输错了。