Rafael Eberle
Rafael Eberle

Reputation: 99

Is there a more efficient way to use the Linq Last() command?

I have a huge PostgresDB machine data table (with TimeScale) and need to get the the last position of a machine. I know, the most efficient way would be a continuous aggregation each day with timescale and and save the last position. But that's not the point of this Question ;)

So, I'm using Linq to do the SQL Request. I have tried some different Method to get the Last Position of the Machine, which I now explain below. I have to mention that the Duration of each function is that huge, because I'm testing it with a list of 60 machine.

  1. LINQ function last() -> Duration: 132s / Needs a lot of RAM because Last() is calculating outside of the Database. There is a huge data transfer between Database and Program because LINQ can't translate Last() to SQL.

    gpsPositionDto.Latitude = _context.MeasureValues.Last(c => c.MachineId == machine && c.MeasureValueId == 80).Value;
    
  2. LINQ function OrderByDescending().First() -> Duration: 114s / Database is needing RAM because the calculation is done inside the Database. So there is no huge data transfer between the Database and Program.

    gpsPositionDto.Latitude = _context.MeasureValues.OrderByDescending(c => c.Timestamp).First(c => c.MachineId == machine && c.MeasureValueId == 80).Value;
    
  3. LINQ function first() -> Duration: 30s / I know, this don't give me the right Value, but I wanted to try it out to see how long this needs.

    gpsPositionDto.Latitude = _context.MeasureValues.First(c => c.MachineId == machine && c.MeasureValueId == 80).Value;
    

Is there any possibility to get a similar Duration to first(), but that I get the correct Data? Because I will execute this function once an Hour for further calculation and we get more and more Machine's inside this List.

Upvotes: 0

Views: 106

Answers (1)

James Curran
James Curran

Reputation: 103575

gpsPositionDto.Latitude = 
      _context.MeasureValues
              .Last(c => c.MachineId == machine && c.MeasureValueId == 80).Value;

This doesn't really have a meaning. Without an OrderBy, "First" and "Last" has no meaning. I tried replicating use cases using the Northwind database on Microsoft SQL Express. It wouldn't even let me do a .Last() on a table.

Orders.Last(o=>o.CustomerID == "TOMSP")

"NotSupportedException••• The query operator 'Last' is not supported."

Your option 2 worked fine:

Orders.OrderByDescending(o =>o.OrderDate ).First(o=>o.CustomerID == "TOMSP")

generating this SQL:

-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'TOMSP'
-- EndRegion
SELECT TOP(1)[t0].[OrderID], [t0].[CustomerID],
             [t0].[EmployeeID], [t0].[OrderDate], 
             [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM[Orders] AS[t0]
WHERE [t0].[CustomerID] = @p0
ORDER BY[t0].[OrderDate] DESC

It's possible that, for Option 1, Postgres is effective doing:

Orders.ToList().Last(o=>o.CustomerID == "TOMSP")

reading the entire table into memory, and then searching on it there, which could explain the bad timings for that.

Upvotes: 2

Related Questions