From 829e97024c2b73dd67bfd8a04c65f03be556eec8 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Sun, 28 May 2023 17:43:30 +0200 Subject: [PATCH] Add a "GROUP BY" clause on queries with RBAC entries As reported in the Neutron patch [1], this change introduce a "GROUP BY" clause on the SQL queries with RBAC entries. With [1], all resouces with RBAC entries ('network', 'qospolicy', 'securitygroup', 'addressscope', 'subnetpool', 'addressgroup') will load the RBAC entries with "joined" strategy. Because of the low cardinality of the RBAC query when all the RBAC registers are in one single project, this patch groups the resource queries by the resource ID. That will reduce the results returned by the SQL engine to only the singular registers required. [1]https://review.opendev.org/c/openstack/neutron/+/884877 Related-Bug: #1918145 Change-Id: I800e0356714d59ba93ab6252c77be0a82f024055 --- neutron_lib/db/model_query.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/neutron_lib/db/model_query.py b/neutron_lib/db/model_query.py index 20976fc88..b722fc2a3 100644 --- a/neutron_lib/db/model_query.py +++ b/neutron_lib/db/model_query.py @@ -108,6 +108,7 @@ def query_with_hooks(context, model, field=None, lazy_fields=None): :param lazy_fields: list of fields for lazy loading :returns: The query with hooks applied to it. """ + group_by = None if field: if hasattr(model, field): field = getattr(model, field) @@ -129,6 +130,11 @@ def query_with_hooks(context, model, field=None, lazy_fields=None): [constants.ACCESS_SHARED, constants.ACCESS_READONLY]) & ((rbac_model.target_project == context.tenant_id) | (rbac_model.target_project == '*')))) + # This "group_by" clause will limit the number of registers + # returned by the query, avoiding the problem of the low SQL + # query cardinality when the RBAC registers are in the requested + # project ID. + group_by = model.id elif hasattr(model, 'shared'): query_filter = ((model.tenant_id == context.tenant_id) | (model.shared == sql.true())) @@ -149,6 +155,9 @@ def query_with_hooks(context, model, field=None, lazy_fields=None): if query_filter is not None: query = query.filter(query_filter) + if group_by: + query = query.group_by(group_by) + if lazy_fields: for field in lazy_fields: query = query.options(lazyload(field))