aprs.me/priv/repo/migrations/20250714210000_optimize_insert_performance.exs

78 lines
2.9 KiB
Elixir

defmodule Aprsme.Repo.Migrations.OptimizeInsertPerformance do
use Ecto.Migration
@disable_ddl_transaction true
@disable_migration_lock true
def up do
# Drop heavy indexes that slow down INSERTs and recreate with better selectivity
# Drop the covering index - it's expensive for INSERTs and rarely used
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_sender_received_covering_idx"
# Drop the weather index and recreate with more selectivity
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_weather_recent_idx"
# Create a more selective weather index that only includes recent data
execute """
CREATE INDEX CONCURRENTLY IF NOT EXISTS packets_weather_selective_idx
ON packets(received_at DESC)
WHERE data_type IN ('weather', 'Weather', 'WX', 'wx')
"""
# Create a partial index for device lookups that only includes recent data
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_device_received_idx"
execute """
CREATE INDEX CONCURRENTLY IF NOT EXISTS packets_device_recent_idx
ON packets(device_identifier, received_at DESC)
WHERE device_identifier IS NOT NULL
"""
# Optimize the spatial index to be partial for better INSERT performance
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_location_recent_idx"
execute """
CREATE INDEX CONCURRENTLY IF NOT EXISTS packets_location_selective_idx
ON packets USING GIST (location)
WHERE has_position = true
"""
# Add a lightweight index just for the most common query pattern - recent data only
create_if_not_exists index(:packets, [:received_at],
name: :packets_recent_hour_idx,
concurrently: true
)
end
def down do
# Restore the original indexes
execute """
CREATE INDEX CONCURRENTLY IF NOT EXISTS packets_sender_received_covering_idx
ON packets(sender, received_at DESC)
INCLUDE (lat, lon, data_type, has_position)
"""
execute """
CREATE INDEX CONCURRENTLY IF NOT EXISTS packets_weather_recent_idx
ON packets(received_at DESC)
WHERE data_type IN ('weather', 'Weather', 'WX', 'wx')
"""
create_if_not_exists index(:packets, [:device_identifier, :received_at],
name: :packets_device_received_idx,
concurrently: true
)
execute """
CREATE INDEX CONCURRENTLY IF NOT EXISTS packets_location_recent_idx
ON packets USING GIST (location)
WHERE has_position = true
"""
# Drop the new selective indexes
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_weather_selective_idx"
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_device_recent_idx"
execute "DROP INDEX CONCURRENTLY IF EXISTS packets_location_selective_idx"
drop_if_exists index(:packets, [:received_at], name: :packets_recent_hour_idx)
end
end