diff --git a/lib/towerops/snmp.ex b/lib/towerops/snmp.ex index 8ebd814b..d060fdb9 100644 --- a/lib/towerops/snmp.ex +++ b/lib/towerops/snmp.ex @@ -227,6 +227,35 @@ defmodule Towerops.Snmp do |> Repo.one() end + @doc """ + Gets the latest sensor readings for multiple sensors in a single query. + + Returns a map of %{sensor_id => reading} for efficient batch loading. + Sensors without readings will not be present in the map. + + ## Examples + + iex> get_latest_sensor_readings_batch([sensor_id1, sensor_id2]) + %{sensor_id1 => %SensorReading{}, sensor_id2 => %SensorReading{}} + """ + def get_latest_sensor_readings_batch(sensor_ids) when is_list(sensor_ids) do + if Enum.empty?(sensor_ids) do + %{} + else + # Use DISTINCT ON to get only the latest reading per sensor + query = + from(r in SensorReading, + where: r.sensor_id in ^sensor_ids, + distinct: r.sensor_id, + order_by: [asc: r.sensor_id, desc: r.checked_at] + ) + + query + |> Repo.all() + |> Map.new(fn reading -> {reading.sensor_id, reading} end) + end + end + # Interface stats queries @doc """ @@ -268,6 +297,35 @@ defmodule Towerops.Snmp do |> Repo.one() end + @doc """ + Gets the latest interface stats for multiple interfaces in a single query. + + Returns a map of %{interface_id => stat} for efficient batch loading. + Interfaces without stats will not be present in the map. + + ## Examples + + iex> get_latest_interface_stats_batch([if_id1, if_id2]) + %{if_id1 => %InterfaceStat{}, if_id2 => %InterfaceStat{}} + """ + def get_latest_interface_stats_batch(interface_ids) when is_list(interface_ids) do + if Enum.empty?(interface_ids) do + %{} + else + # Use DISTINCT ON to get only the latest stat per interface + query = + from(s in InterfaceStat, + where: s.interface_id in ^interface_ids, + distinct: s.interface_id, + order_by: [asc: s.interface_id, desc: s.checked_at] + ) + + query + |> Repo.all() + |> Map.new(fn stat -> {stat.interface_id, stat} end) + end + end + @doc """ Records a new sensor reading. """ diff --git a/lib/towerops_web/live/equipment_live/show.ex b/lib/towerops_web/live/equipment_live/show.ex index 958e5d04..3c5f00b4 100644 --- a/lib/towerops_web/live/equipment_live/show.ex +++ b/lib/towerops_web/live/equipment_live/show.ex @@ -215,17 +215,23 @@ defmodule ToweropsWeb.EquipmentLive.Show do %{device: nil, interfaces: [], sensors: []} device -> - # Preload latest readings for sensors + # Batch load latest readings for all sensors in a single query + sensor_ids = Enum.map(device.sensors, & &1.id) + latest_readings_map = Snmp.get_latest_sensor_readings_batch(sensor_ids) + sensors_with_readings = Enum.map(device.sensors, fn sensor -> - latest_reading = Snmp.get_latest_sensor_reading(sensor.id) + latest_reading = Map.get(latest_readings_map, sensor.id) Map.put(sensor, :latest_reading, latest_reading) end) - # Preload latest stats for interfaces + # Batch load latest stats for all interfaces in a single query + interface_ids = Enum.map(device.interfaces, & &1.id) + latest_stats_map = Snmp.get_latest_interface_stats_batch(interface_ids) + interfaces_with_stats = Enum.map(device.interfaces, fn interface -> - latest_stat = Snmp.get_latest_interface_stat(interface.id) + latest_stat = Map.get(latest_stats_map, interface.id) Map.put(interface, :latest_stat, latest_stat) end)