【发布时间】:2021-07-20 06:34:00
【问题描述】:
好吧,所以我也遇到了我认为是 Greatest-N-Per 问题,而这个问题在我认为 Linq 还没有很好地解决之前已经得到了回答。我有一个包含几百万个条目的表,因此查询需要很多时间。我希望这些查询花费不到一秒,而目前它们花费大约 10 秒才能到达无穷大。
var query =
from MD in _context.MeasureDevice
where MD.DbdistributorMap.DbcustomerId == 6 // Filter the devices based on customer
select new
{
DbMeasureDeviceId = MD.DbMeasureDeviceId,
// includes measurements and alarms which have 1-m and 1-m relations
Measure = _context.Measures.Include(e=> e.MeasureAlarms)
.FirstOrDefault(e => e.DbMeasureDeviceId == MD.DbMeasureDeviceId && e.MeasureTimeStamp == _context.Measures
.Where(x => x.DbMeasureDeviceId == MD.DbMeasureDeviceId)
.Max(e=> e.MeasureTimeStamp)),
Address = MD.Dbaddress // includes address 1-1 relation
};
在此查询中,我从 4 个不同的表中选择数据。首先是 MeasureDevice 表,它是我之后的主要实体。其次,我想要测量表中的最新测量值,如果存在的话,它还应该包括来自另一个表的警报。最后我需要设备的地址,它位于它自己的表中。
有几千台设备,但它们之间有几千个测量值,在测量表中达到几百万行。
我想知道是否有人知道如何使用 EF5 提高 Linq 查询的性能,或者有任何更好的方法来解决 Greatest-N-Per 问题。我使用 Microsoft SQL Server Manager 分析了查询,大部分时间都花在了获取测量值上。
根据要求生成查询:
SELECT [w].[DBMeasureDeviceID], [t].[DBMeasureID], [t].[AlarmDBAlarmID], [t].[batteryValue], [t].[DBMeasureDeviceID], [t].[MeasureTimeStamp], [t].[Stand], [t].[Temperature], [t].[c], [a].[DBAddressID], [a].[AmountAvtalenummere],
[a].[DBOwnerID], [a].[Gate], [a].[HouseCharacter], [a].[HouseNumber], [a].[Latitude], [a].[Longitude], [d].[DBDistributorMapID], [m1].[DBMeasureID], [m1].[DBAlarmID], [m1].[AlarmDBAlarmID], [m1].[MeasureDBMeasureID]
FROM [MeasureDevice] AS [w]
INNER JOIN [DistribrutorMap] AS [d] ON [w].[DBDistributorMapID] = [d].[DBDistributorMapID]
LEFT JOIN [Address] AS [a] ON [w].[DBAddressID] = [a].[DBAddressID]
OUTER APPLY (
SELECT TOP(1) [m].[DBMeasureID], [m].[AlarmDBAlarmID], [m].[batteryValue], [m].[DBMeasureDeviceID], [m].[MeasureTimeStamp], [m].[Stand], [m].[Temperature], 1 AS [c]
FROM [Measure] AS [m]
WHERE ([m].[MeasureTimeStamp] = (
SELECT MAX([m0].[MeasureTimeStamp])
FROM [Measure] AS [m0]
WHERE [m0].[DBMeasureDeviceID] = [w].[DBMeasureDeviceID])) AND ([w].[DBMeasureDeviceID] = [m].[DBMeasureDeviceID])
) AS [t]
LEFT JOIN [MeasureAlarm] AS [m1] ON [t].[DBMeasureID] = [m1].[MeasureDBMeasureID]
WHERE [d].[DBCustomerID] = 6
ORDER BY [w].[DBMeasureDeviceID], [d].[DBDistributorMapID], [a].[DBAddressID], [t].[DBMeasureID], [m1].[DBMeasureID], [m1].[DBAlarmID]
实体关系
【问题讨论】:
-
恕我直言,使用导航属性构建这种类型的查询更容易。
_context.Measure.Where(m => m.MeasureTimeStamp == m.Device.Measure.Max(m2 => m2.MeasureTimeStamp))。但是性能会更好吗? -
@mjwills 添加到编辑中
-
@JeremyLakeman 似乎对性能几乎没有影响。运行大约需要 10 秒
-
一些备注: 1. 更常见的顺序是
MeasureTimeStamp降序取第一条记录。 2.查看类模型(+导航属性)会有所帮助。 3. 您显示的查询看起来不像 EF6 会生成的内容。这是正确的版本吗? -
@GertArnold 使用的是 EF5 而不是 EF6,是一个错字。在编辑中修复。将尝试生成描述关系的图表
标签: c# .net entity-framework linq