@@ -206,27 +206,39 @@ def _analyze_many2one_dimension(
206206 overall_coverage ,
207207 partner_model ,
208208 ):
209- """Analyze a Many2one field dimension."""
209+ """Analyze a Many2one field dimension.
210+
211+ Uses read_group to count population and beneficiaries per group in two
212+ database queries rather than loading all records into memory.
213+ """
210214 group_results = []
211215 worst_ratio = 1.0
212216
213- # Get distinct values from population using mapped() to avoid N+1
214- population = partner_model .search (base_domain )
215- values = set (population .mapped (f"{ field_name } .id" ))
216- values .discard (False )
217-
218- for value_id in values :
219- related_record = self .env [partner_model ._fields [field_name ].comodel_name ].browse (value_id )
220-
221- group_domain = base_domain + [(field_name , "=" , value_id )]
222- group_total = partner_model .search_count (group_domain )
217+ # Population counts per group - one query
218+ population_groups = partner_model .read_group (base_domain , [field_name ], [field_name ])
219+ # Beneficiary counts per group - one query
220+ beneficiary_domain = base_domain + [("id" , "in" , list (beneficiary_set ))]
221+ beneficiary_groups = partner_model .read_group (beneficiary_domain , [field_name ], [field_name ])
222+
223+ # Build lookup dict from group value -> beneficiary count
224+ # read_group returns the Many2one field as (id, display_name) tuple or False
225+ beneficiary_counts = {}
226+ for row in beneficiary_groups :
227+ value = row [field_name ]
228+ value_id = value [0 ] if value else False
229+ beneficiary_counts [value_id ] = row [f"{ field_name } _count" ]
230+
231+ for row in population_groups :
232+ value = row [field_name ]
233+ if not value :
234+ continue
235+ value_id , display_name = value
236+ group_total = row [f"{ field_name } _count" ]
223237
224238 if group_total == 0 :
225239 continue
226240
227- # Count beneficiaries in this group
228- beneficiary_domain = group_domain + [("id" , "in" , list (beneficiary_set ))]
229- group_beneficiaries = partner_model .search_count (beneficiary_domain )
241+ group_beneficiaries = beneficiary_counts .get (value_id , 0 )
230242 group_coverage = group_beneficiaries / group_total
231243
232244 disparity_ratio = self ._compute_disparity_ratio (group_coverage , overall_coverage )
@@ -235,7 +247,7 @@ def _analyze_many2one_dimension(
235247 status = self ._get_disparity_status (disparity_ratio )
236248 # For Many2one fields, prefer display_name over dimension label mapping
237249 # since label mappings may use codes rather than database IDs
238- label = related_record . display_name or dimension .get_label_for_value (str (value_id ))
250+ label = display_name or dimension .get_label_for_value (str (value_id ))
239251
240252 group_results .append (
241253 {
@@ -269,31 +281,47 @@ def _analyze_selection_dimension(
269281 overall_coverage ,
270282 partner_model ,
271283 ):
272- """Analyze a Selection field dimension."""
284+ """Analyze a Selection field dimension.
285+
286+ Uses read_group to count population and beneficiaries per group in two
287+ database queries rather than one search_count pair per selection value.
288+ """
273289 group_results = []
274290 worst_ratio = 1.0
275291
276292 field = partner_model ._fields [field_name ]
277293 selection = field .selection
278294 if callable (selection ):
279295 selection = selection (partner_model )
296+ # Build label lookup from the field's selection values
297+ label_by_key = dict (selection )
280298
281- for key , label in selection :
282- group_domain = base_domain + [(field_name , "=" , key )]
283- group_total = partner_model .search_count (group_domain )
299+ # Population counts per group - one query
300+ population_groups = partner_model .read_group (base_domain , [field_name ], [field_name ])
301+ # Beneficiary counts per group - one query
302+ beneficiary_domain = base_domain + [("id" , "in" , list (beneficiary_set ))]
303+ beneficiary_groups = partner_model .read_group (beneficiary_domain , [field_name ], [field_name ])
304+
305+ # Build lookup dict from selection key -> beneficiary count
306+ beneficiary_counts = {row [field_name ]: row [f"{ field_name } _count" ] for row in beneficiary_groups }
307+
308+ for row in population_groups :
309+ key = row [field_name ]
310+ if key is False :
311+ continue
312+ group_total = row [f"{ field_name } _count" ]
284313
285314 if group_total == 0 :
286315 continue
287316
288- beneficiary_domain = group_domain + [("id" , "in" , list (beneficiary_set ))]
289- group_beneficiaries = partner_model .search_count (beneficiary_domain )
317+ group_beneficiaries = beneficiary_counts .get (key , 0 )
290318 group_coverage = group_beneficiaries / group_total
291319
292320 disparity_ratio = self ._compute_disparity_ratio (group_coverage , overall_coverage )
293321 worst_ratio = min (worst_ratio , disparity_ratio )
294322
295323 status = self ._get_disparity_status (disparity_ratio )
296- display_label = dimension .get_label_for_value (key ) or label
324+ display_label = dimension .get_label_for_value (key ) or label_by_key . get ( key , key )
297325
298326 group_results .append (
299327 {
@@ -327,19 +355,31 @@ def _analyze_boolean_dimension(
327355 overall_coverage ,
328356 partner_model ,
329357 ):
330- """Analyze a Boolean field dimension."""
358+ """Analyze a Boolean field dimension.
359+
360+ Uses read_group to count population and beneficiaries per group in two
361+ database queries rather than one search_count pair per boolean value.
362+ """
331363 group_results = []
332364 worst_ratio = 1.0
333365
334- for value in [True , False ]:
335- group_domain = base_domain + [(field_name , "=" , value )]
336- group_total = partner_model .search_count (group_domain )
366+ # Population counts per group - one query
367+ population_groups = partner_model .read_group (base_domain , [field_name ], [field_name ])
368+ # Beneficiary counts per group - one query
369+ beneficiary_domain = base_domain + [("id" , "in" , list (beneficiary_set ))]
370+ beneficiary_groups = partner_model .read_group (beneficiary_domain , [field_name ], [field_name ])
371+
372+ # Build lookup dict from boolean value -> beneficiary count
373+ beneficiary_counts = {row [field_name ]: row [f"{ field_name } _count" ] for row in beneficiary_groups }
374+
375+ for row in population_groups :
376+ value = row [field_name ]
377+ group_total = row [f"{ field_name } _count" ]
337378
338379 if group_total == 0 :
339380 continue
340381
341- beneficiary_domain = group_domain + [("id" , "in" , list (beneficiary_set ))]
342- group_beneficiaries = partner_model .search_count (beneficiary_domain )
382+ group_beneficiaries = beneficiary_counts .get (value , 0 )
343383 group_coverage = group_beneficiaries / group_total
344384
345385 disparity_ratio = self ._compute_disparity_ratio (group_coverage , overall_coverage )
0 commit comments