From ff3a478bbdcf3e9de41728eb1a987473a71ed00e Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 1 Jun 2026 16:49:48 -0500 Subject: [PATCH] perf: add LIMIT to unbounded DISTINCT ON, guard device table scan, add DB indexes Bound batch DISTINCT ON queries by input count. Guard Repo.all(Devices) with exists? check. Add trigram GIN index on base_callsign and (has_weather, received_at DESC) partial index. Ultraworked with Sisyphus Co-authored-by: Sisyphus --- lib/aprsme/device_identification.ex | 18 ++++++++---------- lib/aprsme/packets/prepared_queries.ex | 4 ++++ ...1000001_add_base_callsign_trigram_index.exs | 17 +++++++++++++++++ ...00002_add_has_weather_received_at_index.exs | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 priv/repo/migrations/20260601000001_add_base_callsign_trigram_index.exs create mode 100644 priv/repo/migrations/20260601000002_add_has_weather_received_at_index.exs diff --git a/lib/aprsme/device_identification.ex b/lib/aprsme/device_identification.ex index c660342..a26b9f0 100644 --- a/lib/aprsme/device_identification.ex +++ b/lib/aprsme/device_identification.ex @@ -228,17 +228,15 @@ defmodule Aprsme.DeviceIdentification do end defp lookup_device_from_db(identifier) do - # Fetch all device patterns from DB - devices = - try do - Repo.all(Devices) - rescue - _ -> [] - end + if Repo.exists?(from(d in Devices, limit: 1)) do + devices = Repo.all(Devices) - Enum.find(devices, fn device -> - pattern_matches?(device.identifier, identifier) - end) + Enum.find(devices, fn device -> + pattern_matches?(device.identifier, identifier) + end) + end + rescue + _ -> nil end defp pattern_matches?(pattern, identifier) do diff --git a/lib/aprsme/packets/prepared_queries.ex b/lib/aprsme/packets/prepared_queries.ex index fd7f908..659aae7 100644 --- a/lib/aprsme/packets/prepared_queries.ex +++ b/lib/aprsme/packets/prepared_queries.ex @@ -56,12 +56,14 @@ defmodule Aprsme.Packets.PreparedQueries do def get_latest_packets_for_callsigns(callsigns) when is_list(callsigns) do normalized = Enum.map(callsigns, &String.upcase(String.trim(&1))) + limit = length(callsigns) Repo.all( from(p in Packet, where: fragment("upper(?)", p.sender) in ^normalized, distinct: fragment("upper(?)", p.sender), order_by: [asc: fragment("upper(?)", p.sender), desc: p.received_at], + limit: ^limit, select: %{p | lat: fragment("ST_Y(?)", p.location), lon: fragment("ST_X(?)", p.location)} ) ) @@ -77,6 +79,7 @@ defmodule Aprsme.Packets.PreparedQueries do def get_latest_positions_for_callsigns(callsigns) when is_list(callsigns) do normalized = Enum.map(callsigns, &String.upcase(String.trim(&1))) + limit = length(callsigns) Repo.all( from(p in Packet, @@ -84,6 +87,7 @@ defmodule Aprsme.Packets.PreparedQueries do where: not is_nil(p.location), distinct: fragment("upper(?)", p.sender), order_by: [asc: fragment("upper(?)", p.sender), desc: p.received_at], + limit: ^limit, select: %{callsign: p.sender, lat: fragment("ST_Y(?)", p.location), lng: fragment("ST_X(?)", p.location)} ) ) diff --git a/priv/repo/migrations/20260601000001_add_base_callsign_trigram_index.exs b/priv/repo/migrations/20260601000001_add_base_callsign_trigram_index.exs new file mode 100644 index 0000000..63c6793 --- /dev/null +++ b/priv/repo/migrations/20260601000001_add_base_callsign_trigram_index.exs @@ -0,0 +1,17 @@ +defmodule Aprsme.Repo.Migrations.AddBaseCallsignTrigramIndex do + use Ecto.Migration + @disable_ddl_transaction true + @disable_migration_lock true + + def up do + execute """ + CREATE INDEX IF NOT EXISTS idx_packets_base_callsign_trgm + ON packets USING gin (base_callsign gin_trgm_ops) + WHERE base_callsign IS NOT NULL + """ + end + + def down do + execute "DROP INDEX IF EXISTS idx_packets_base_callsign_trgm" + end +end diff --git a/priv/repo/migrations/20260601000002_add_has_weather_received_at_index.exs b/priv/repo/migrations/20260601000002_add_has_weather_received_at_index.exs new file mode 100644 index 0000000..479937d --- /dev/null +++ b/priv/repo/migrations/20260601000002_add_has_weather_received_at_index.exs @@ -0,0 +1,17 @@ +defmodule Aprsme.Repo.Migrations.AddHasWeatherReceivedAtIndex do + use Ecto.Migration + @disable_ddl_transaction true + @disable_migration_lock true + + def up do + execute """ + CREATE INDEX IF NOT EXISTS idx_packets_has_weather_time + ON packets (has_weather, received_at DESC) + WHERE has_weather = true + """ + end + + def down do + execute "DROP INDEX IF EXISTS idx_packets_has_weather_time" + end +end