perf(mnesia): use secondary indexes in booking, event, search, review

Replace hot-path dirty_match_object scans with dirty_index_read and batch
calendar lookup in search to cut N+1 enrichment cost.
This commit is contained in:
2026-08-03 22:55:50 +03:00
parent 104892bdde
commit e3467e7412
4 changed files with 84 additions and 28 deletions
+9 -6
View File
@@ -54,8 +54,8 @@ get_by_id(Id) ->
%%%-------------------------------------------------------------------
-spec list_by_event(EventId :: binary()) -> {ok, [#booking{}]}.
list_by_event(EventId) ->
Match = #booking{event_id = EventId, _ = '_'},
Bookings = mnesia:dirty_match_object(Match),
%% Optimized: use event_id index instead of full table scan.
Bookings = mnesia:dirty_index_read(booking, EventId, #booking.event_id),
{ok, Bookings}.
%%%-------------------------------------------------------------------
@@ -64,8 +64,8 @@ list_by_event(EventId) ->
%%%-------------------------------------------------------------------
-spec list_by_user(UserId :: binary()) -> {ok, [#booking{}]}.
list_by_user(UserId) ->
Match = #booking{user_id = UserId, _ = '_'},
Bookings = mnesia:dirty_match_object(Match),
%% Optimized: use user_id index instead of full table scan.
Bookings = mnesia:dirty_index_read(booking, UserId, #booking.user_id),
{ok, Bookings}.
%%%-------------------------------------------------------------------
@@ -74,6 +74,7 @@ list_by_user(UserId) ->
%%%-------------------------------------------------------------------
-spec list_all() -> [#booking{}].
list_all() ->
%% Genuinely lists all bookings (admin view); no index can help here.
mnesia:dirty_match_object(#booking{_ = '_'}).
%%%-------------------------------------------------------------------
@@ -123,8 +124,10 @@ count_bookings() ->
-spec get_by_event_and_user(EventId :: binary(), UserId :: binary()) ->
{ok, #booking{}} | {error, not_found}.
get_by_event_and_user(EventId, UserId) ->
Match = #booking{event_id = EventId, user_id = UserId, _ = '_'},
case mnesia:dirty_match_object(Match) of
%% Optimized: use event_id index, then filter by user_id
%% instead of a full table scan.
Candidates = mnesia:dirty_index_read(booking, EventId, #booking.event_id),
case [B || B <- Candidates, B#booking.user_id =:= UserId] of
[] -> {error, not_found};
[Booking] -> {ok, Booking}
end.