Я запрашиваю базу данных SQL, используя Linq и Entity Framework Core в проекте Razorpages для создания графика резидентности, вот тот, который я сделал ранее.
Я изо всех сил пытаясь оптимизировать этот запрос, несмотря на многочисленные попытки и итерации, он медленный и часто выходит из строя. Мне нужен окончательный массив значений Count (), которые составляют каждый квадрат резидентного графика, и я не заинтересован в необработанных данных.
Данные взяты из таблицы с ~ 80 миллионами строк, и я нашел решения от SO, которые могли бы работать с меньшим количеством записей, но которые не подходят в этом случае использования (обычно поиск Linq, group, join). Я думаю, что проблема заключается в комбинации фильтров, групп и объединений, за которыми следует подсчет, происходящий на стороне сервера без предварительной загрузки необработанных данных.
Просмотр команды SQL в SSMS (извлечено из LINQPad) очень плохо оптимизирован - я могу опубликовать это, если это будет полезно, но он состоит из 236 строк, состоящих из повторяющихся секций.
Linq, который я собрал вместе, выполняет необходимую операцию в 4 шагах, описанных здесь.
Шаг 1 (строки между определенным временем, с определенным LocationTypeId и channelId = engSpeed):
var speedRows = context.TestData
.Where(a => a.Time >= start
&& a.Time < end
&& a.LocationTypeId == 3
&& a.channelId == 7)
.Select(s => new
{
s.Time,
s.ChannelValue
})
.Distinct();
Шаг 2 (строки с Идентификатор канала = крутящий момент):
var torqueRows = context.TestData
.Where(a => a.LocationTypeId == 3
&& a.channelId == 8)
.Select(s => new
{
s.Time,
s.ChannelValue
})
.Distinct();
Шаг 3 (объедините ряды скорости и крутящего момента из Шаг 1 и Шаг 2 по времени ):
var joinedRows = speedRows.Join(torqueRows, arg => arg.Time, arg => arg.Time,
(speed, torque) => new
{
Id = speed.Time,
Speed = Convert.ToDouble(speed.ChannelValue),
Torque = Convert.ToInt16(torque.ChannelValue)
});
Шаг 4 (создайте динамические c группировки, используя объединенную таблицу из Шаг 3 ):
var response = (from a in joinedRows
group a by (a.Torque / 100) into torqueGroup
orderby torqueGroup.Key
select new
{
TorqueBracket = $"{100 * torqueGroup.Key} <> {100 + (100 * torqueGroup.Key)}",
TorqueMin = 100 * torqueGroup.Key,
TorqueMax = 100 + (100 * torqueGroup.Key),
Speeds = (from d in torqueGroup
group d by (Math.Floor((d.Speed) / 500)) into speedGroup
orderby speedGroup.Key
select new
{
SpeedBracket = $"{500 * speedGroup.Key} <> {500 + (500 * speedGroup.Key)}",
SpeedMin = 500 * (int)speedGroup.Key,
SpeedMax = 500 + (500 * (int)speedGroup.Key),
Minutes = speedGroup.Count()
})
}).ToList();
Я мог упустить что-то очевидное, но я пробовал много попыток, и это лучшее, что я получил.
Класс TestData
:
public partial class TestData {
public int LiveDataId { get; set; }
public DateTime? Time { get; set; }
public int? LocationTypeId { get; set; }
public int? TestNo { get; set; }
public int? LogNo { get; set; }
public int? LiveDataChannelId { get; set; }
public decimal? ChannelValue { get; set; }
public virtual LiveDataChannelNames LiveDataChannel { get; set; }
public virtual LocationType LocationType { get; set; }
}
Любая помощь или указатели будут оценены.
Спасибо.