我真的需要这个帮助,经过几个小时的搜索后找不到相关的答案。
MySQL,Entity Framework 6,拥有数百万条记录的数据库,记录如下:
Indexint(11)NOT NULL
TaskIDint(11)NOT NULL
DeviceIDbigint(20)NOT NULL
Commentslongtext NULL
ExtendedResultslongtext NULL
RunResultint(11)NOT NULL
JobResultint(11)NOT NULL
JobResultValuedouble NOT NULL
ReporterIDbigint(20)NOT NULL
FieldIDbigint(20)NOT NULL
TimeOfRundatetime NOT NULL
我需要的是获取特定任务ID的所有记录,然后按DeviceID分组并按TimeOfRun排序,以获取特定任务ID中每个deviceID的最新数据。
这是我的代码:
List<JobsRecordHistory> newH = db.JobsRecordHistories.AsNoTracking().Where(x => x.TaskID == taskID).GroupBy(x => x.DeviceID).
Select(x => x.OrderByDescending(y => y.TimeOfRun).FirstOrDefault()).ToList();
但这是生成的查询:
{SELECT
Apply1
。Index
,
Apply1
。TaskID
,
Apply1
。DEVICEID1
AS DeviceID
,
Apply1
。RunResult
,
Apply1
。JobResult
,
Apply1
。JobResultValue
,
Apply1
。ExtendedResults
,
Apply1
。Comments
,
Apply1
。ReporterID
,
Apply1
。FieldID
,
Apply1
。TimeOfRun
FROM(选择
Project2
。p__linq__0
,
Project2
。DeviceID
,
(选择
Project3
。Index
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS Index
,
(选择
Project3
。TaskID
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS TaskID
,
(选择
Project3
。DeviceID
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS DEVICEID1
,
(选择
Project3
。RunResult
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS RunResult
,
(选择
Project3
。JobResult
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS JobResult
,
(选择
Project3
。JobResultValue
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS JobResultValue
,
(选择
Project3
。ExtendedResults
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS ExtendedResults
,
(选择
Project3
。Comments
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS Comments
,
(选择
Project3
。ReporterID
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS ReporterID
,
(选择
Project3
。FieldID
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS FieldID
,
(选择
Project3
。TimeOfRun
来自JobsRecordHistories
AS Project3
WHERE(Project3
。TaskID
= @ p__linq__0)AND(Project2
。DeviceID
= Project3
。DeviceID
)
订购
Project3
。TimeOfRun
DESC限制1)AS TimeOfRun
FROM(选择
@ p__linq__0 AS p__linq__0
,
Distinct1
。DeviceID
FROM(SELECT DISTINCT
Extent1
。DeviceID
来自JobsRecordHistories
AS Extent1
WHERE Extent1
。TaskID
= @ p__linq__0)AS Distinct1
)AS Project2
)AS Apply1
}
这太长了。
我承认,我不太了解SQL,但是如果在WHERE语句之后插入一个ToList(),那么我会更快地得到结果,尽管它仍然不是正确的事情,因为有很多不需要的数据在这种情况下数据库传递给我的应用程序,对于40k记录,它仍然很慢= 30秒。
我也试过这个:
Dictionary<long, DateTime> DeviceIDAndTime = db.JobsRecordHistories.AsNoTracking().Where(x => x.TaskID == taskID).GroupBy(x => x.DeviceID)
.Select(g => new DeviceIDaAndTime { deviceID = g.Key, timeOfRun = g.Max(gi => gi.TimeOfRun) }).ToDictionary(x => x.deviceID, x => x.timeOfRun);
为了以这种方式使用字典:
List<JobsRecordHistory> newH = db.JobsRecordHistories.AsNoTracking().Where(x => DeviceIDAndTime.Keys.Contains(x.DeviceID) && x.TimeOfRun == DeviceIDAndTime[x.DeviceID]).ToList();
但是我收到了这个错误:
Additional information: LINQ to Entities does not recognize the method 'System.DateTime get_Item(Int64)' method, and this method cannot be translated into a store expression.
根据我的理解,这是有道理的,在将timeOfRun与字典值进行比较时,LINQ在编写查询时需要特定的值而不是集合。
我很奇怪,我没有找到任何相关的帖子,而其他人没有遇到这个问题。我想我错过了什么。
感谢任何帮助,谢谢
答案 0 :(得分:2)
最终弄明白并提高了表现 我需要一个查询和一个子查询,而且我需要MAX函数而不是ORDER因为我不关心结果的顺序,我只关心最大的(timeOfRun)。 此外,一旦我注意到更大的索引列(我的PK,自动增量)意味着更新近的数据,事情就被简化了,所以我不需要MAX(timeOfRun),而是使用了MAX(索引),尽管我使用了MAX(索引)。我相信它会以同样的方式运作。
这是我的LINQ:
var historyQuery = db.JobsRecordHistories.AsNoTracking().Where(y => y.TaskID == taskID &&
db.JobsRecordHistories.Where(x => x.TaskID == taskID).GroupBy(x => x.DeviceID).Select(g => g.Max(i => i.Index)).Contains<int>(y.Index));
这是生成的SQL:
{SELECT
Extent1
。Index
,
Extent1
。TaskID
,
Extent1
。DeviceID
,
Extent1
。RunResult
,
Extent1
。JobResult
,
Extent1
。JobResultValue
,
Extent1
。ExtendedResults
,
Extent1
。Comments
,
Extent1
。ReporterID
,
Extent1
。FieldID
,
Extent1
。TimeOfRun
来自JobsRecordHistories
AS Extent1
WHERE(Extent1
。TaskID
= @ p__linq__0)AND(EXISTS(SELECT)
1 AS C1
FROM(选择
Extent2
。DeviceID
AS K1
,
MAX(Extent2
。Index
)AS A1
来自JobsRecordHistories
AS Extent2
在Extent2
。TaskID
= @ p__linq__1
通过...分组
Extent2
。DeviceID
)AS GroupBy1
在GroupBy1
。A1
= Extent1
。Index
)}}
我希望这会有所帮助,因为我花了1.5天的谷歌搜索,查看SQL查询,LINQ,调试和优化
答案 1 :(得分:1)
提供查询语法而不是基于镜头的方法。
我没有在本地测试过,但你可能会看到改进的sql生成
或者至少也许这种方法可能会让你走上正确的道路
using System;
using System.Data.Entity;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace EF.CodeFirst
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
using (var db = new TestDbContext())
{
var taskId = 1;
var query = from job in db.JobRecordHistories
where job.TaskId == taskId
orderby job.TimeOfRun descending
group job by job.DeviceId
into deviceGroup
select deviceGroup;
foreach (var deviceGroup in query)
{
foreach (var jobRecordHistory in deviceGroup)
{
Console.WriteLine("DeviceId '{0}', TaskId'{1}' Runtime'{2}'", jobRecordHistory.DeviceId,
jobRecordHistory.TaskId, jobRecordHistory);
}
}
}
}
}
public class TestDbContext : DbContext
{
public DbSet<JobRecordHistory> JobRecordHistories { get; set; }
}
public class JobRecordHistory
{
public int Id { get; set; }
public int TaskId { get; set; }
public int DeviceId { get; set; }
public DateTime TimeOfRun { get; set; }
}
}