Skip to content

Commit a549718

Browse files
fix: Fix the N+1 query issue in EventProceduresController#index (#333)
* fix: Fix the N+1 query issue in EventProceduresController#index caused by repeated database queries in EventProcedures::BuildTotalAmountCents * refactor: creates indexed hashes for O(1) search
1 parent 9fd266d commit a549718

File tree

4 files changed

+48
-15
lines changed

4 files changed

+48
-15
lines changed

app/operations/event_procedures/build_total_amount_cents.rb

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,30 @@ def base_amount_cents
2323
cbhpm_procedure = find_cbhpm_procedure
2424
return 0 unless cbhpm_procedure
2525

26-
port_value = find_port_value(cbhpm_procedure)
27-
return value_for_anesthetic_port_zero(event_procedure) unless port_value
26+
port_value = find_port_value(cbhpm_procedure.anesthetic_port)
27+
return value_for_anesthetic_port_zero unless port_value
2828

2929
port_value.amount_cents.to_i
3030
end
3131

32-
def value_for_anesthetic_port_zero(event_procedure)
33-
port = PortValue.find_by(cbhpm_id: event_procedure.cbhpm_id, anesthetic_port: ANESTHETIC_PORT_ZERO_AMOUNT)
34-
port&.amount_cents.to_i
32+
def value_for_anesthetic_port_zero
33+
port_values_by_anesthetic_port[ANESTHETIC_PORT_ZERO_AMOUNT]&.amount_cents.to_i
3534
end
3635

3736
def find_cbhpm_procedure
38-
CbhpmProcedure.find_by(
39-
procedure_id: event_procedure.procedure_id,
40-
cbhpm_id: event_procedure.cbhpm_id
41-
)
37+
cbhpm_procedures_by_cbhpm_id[event_procedure.cbhpm_id]
4238
end
4339

44-
def find_port_value(cbhpm_procedure)
45-
PortValue.find_by(
46-
cbhpm_id: cbhpm_procedure.cbhpm_id,
47-
anesthetic_port: cbhpm_procedure.anesthetic_port
48-
)
40+
def find_port_value(anesthetic_port)
41+
port_values_by_anesthetic_port[anesthetic_port]
42+
end
43+
44+
def cbhpm_procedures_by_cbhpm_id
45+
@cbhpm_procedures_by_cbhpm_id ||= event_procedure.procedure.cbhpm_procedures.index_by(&:cbhpm_id)
46+
end
47+
48+
def port_values_by_anesthetic_port
49+
@port_values_by_anesthetic_port ||= event_procedure.cbhpm.port_values.index_by(&:anesthetic_port)
4950
end
5051

5152
def apartment_multiplier

app/operations/event_procedures/list.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ def filtered_query
2121
:patient,
2222
:hospital,
2323
:health_insurance,
24-
cbhpm: :port_values
24+
cbhpm: :port_values,
25+
procedure: :cbhpm_procedures
2526
)
2627
apply_all_filters(query)
2728
end

spec/requests/api/v1/event_procedures_request_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@
2828
end
2929
end
3030

31+
context "when checking for N+1 queries" do
32+
it "does not have N+1 queries" do
33+
create_list(:event_procedure, 2, user_id: user.id)
34+
get(path, params: {}, headers: headers) # Warmup
35+
36+
control_count = count_queries { get(path, params: {}, headers: headers) }
37+
38+
create_list(:event_procedure, 5, user_id: user.id)
39+
40+
final_count = count_queries { get(path, params: {}, headers: headers) }
41+
42+
expect(final_count).to be <= control_count
43+
end
44+
end
45+
3146
context "when has filters by month" do
3247
it "returns event_procedures per month" do
3348
create_list(:event_procedure, 3, date: "2023-02-15", user_id: user.id)

spec/support/query_counter.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
module QueryCounter
4+
def count_queries(&)
5+
count = 0
6+
counter_f = lambda { |_name, _started, _finished, _unique_id, payload|
7+
count += 1 unless payload[:name].in? %w[CACHE SCHEMA]
8+
}
9+
ActiveSupport::Notifications.subscribed(counter_f, "sql.active_record", &)
10+
count
11+
end
12+
end
13+
14+
RSpec.configure do |config|
15+
config.include QueryCounter, type: :request
16+
end

0 commit comments

Comments
 (0)