假设我们有(剥离)实体:
Message
{
int MessageID;
int DeviceID;
DateTime Timestamp;
string Value;
};
Device
{
int DeviceID;
string name;
byte Type;
};
我们有10 000台设备,每两台每两分钟发送最多5条状态消息两年,这就是数据库。现在我们想要,比如说 - 500个选择的Type == 254的设备可以创建实时报告,它可以让你选择一段时间,间隔(每天,每2小时,5分钟或5秒)等等每个结果时间戳都会在此时间戳之前收到最后一条消息。我已尝试创建此查询,但无法一次查询一个时间戳(时刻):
DateTime timestamp = // from argument
var query = from message in this.Messages
.Include(msg => msg.Device)
where message.Timestamp <= timestamp
&& msg.Device.Type == 254
group message by message.DeviceID into g
select (from message in g
orderby message.Timestamp descending
select message).FirstOrDefault();
它的作用:它限制了搜索的时间戳(仅在&#34;时间戳之前得到#34;以及#34;时间戳)并按设备对消息进行分组,因此我们每个设备只能获得一条消息。 Orderby descending和FirstOrDefault - 用于获得最高的一个。时间戳上有降序索引。
在循环中运行它的问题是什么?好吧,用户希望用新的数据(最后一天,间隔:1分钟)快速查询很长一段时间,这意味着使用不同的参数(时间戳)重新查询同一查询的数量非常大。对于有限数量的数据,它每秒查询数十次时间戳,并且我认为查询将使用时间戳列表运行一次以便更快地完成。
有没有办法连接同一个查询的多个运行,一次可以获得更大批量的数据?我使用的是EF5但我并不害怕编写存储过程和sql函数。
答案 0 :(得分:2)
除了IntervalID
之外,我还会尝试通过某种“DeviceID
”扩展分组。 IntervalID
将是一个整数,用于表示句点开始和结束之间的间隔。您可以为查询输入三个参数:
DateTime periodStart = ...;
DateTime periodEnd = ...;
int interval = ...; // unit = seconds for example, for 5 minutes it's 300, etc.
评估期内给定消息的IntervalID
是在查询期间“动态”计算的属性,在.NET中它将是:
IntervalID = Math.Floor((msg.Timestamp - periodStart).TotalSeconds / interval);
您很可能无法在LINQ-to-Entities查询中直接使用此表达式,因为可能不支持两个DateTime
值的减运算符。 (LINQ-to-Entities支持Math.Floor
。)但您可以尝试用EntityFunctions
(或DbFunctions
替换EF&gt; = 6)替换它。整个查询可能如下所示:
DateTime periodStart = ...;
DateTime periodEnd = ...;
int interval = ...; // unit = seconds for example, for 5 minutes it's 300, etc.
var query = from message in this.Messages
where message.Timestamp >= periodStart
&& message.Timestamp <= periodEnd
&& message.Device.Type == 254
select new
{
Message = message,
IntervalID = Math.Floor(EntityFunctions.DiffSeconds(
message.TimeStamp, periodStart) / interval)
} into messageInInterval
group messageInInterval by new
{
DeviceID = messageInInterval.Message.DeviceID,
IntervalID = messageInInterval.IntervalID
} into g
select (from messageInInterval in g
orderby messageInInterval.Message.Timestamp descending
select messageInInterval.Message).FirstOrDefault();
query.ToList()
提供一个消息列表,其中包含每个设备和每个时间间隔的最后一条消息。
(只是一个基本想法,代码未经测试。)