Use subqueries for rbac_entries and subnets<->network

Loading subnets as part of the networks list and networks
as part of the subnets list appears to have a significant
impact when the network has tags and the subnets have
extra routes entries. This is even further compounded by
the network having rbac entries (likely due to the subnet
inheriting the RBAC entries of the network with the custom
join condition in the model).

This patch converts rbac_entries on both subnet and network
to use a subquery and converts the network and subnets
relationships on the subnet and network models (respectively)
to use subqueries as well.

On my dev environment after running the script in the report,
a network list took 5 minutes. Converting just the rbac_entries
or just the network/subnet relationship to subqueries reduced it
to 3-5 seconds. Converting both (as this patch does), reduces it
back down to a couple of hundred milliseconds (normal perf of my
development env with the current network count).

Subqueries will just cost us a constant number of queries and
won't scale up with result count so this should not impact scalability
in any way.

None of these fields are queryable from the API, so we don't need
to worry about breaking queries against the models.

Partial-Bug: #1649317
Change-Id: Ic1947e3d78d58a79b21344b10cb7ab0e573e419f
This commit is contained in:
Kevin Benton 2016-12-12 11:36:51 -08:00
parent 14079d0f21
commit a802b382d3
2 changed files with 8 additions and 8 deletions

View File

@ -151,7 +151,7 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
for route in subnet['routes']],
}
# The shared attribute for a subnet is the same as its parent network
res['shared'] = self._is_network_shared(context, subnet.networks)
res['shared'] = self._is_network_shared(context, subnet.rbac_entries)
# Call auxiliary extend functions, if any
self._apply_dict_extend_functions(attributes.SUBNETS, res, subnet)
return db_utils.resource_fields(res, fields)
@ -270,18 +270,18 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
'status': network['status'],
'subnets': [subnet['id']
for subnet in network['subnets']]}
res['shared'] = self._is_network_shared(context, network)
res['shared'] = self._is_network_shared(context, network.rbac_entries)
# Call auxiliary extend functions, if any
if process_extensions:
self._apply_dict_extend_functions(
attributes.NETWORKS, res, network)
return db_utils.resource_fields(res, fields)
def _is_network_shared(self, context, network):
def _is_network_shared(self, context, rbac_entries):
# The shared attribute for a network now reflects if the network
# is shared to the calling tenant via an RBAC entry.
matches = ('*',) + ((context.tenant_id,) if context else ())
for entry in network.rbac_entries:
for entry in rbac_entries:
if (entry.action == 'access_as_shared' and
entry.target_tenant in matches):
return True

View File

@ -186,7 +186,7 @@ class Subnet(standard_attr.HasStandardAttributes, model_base.BASEV2,
# subnets don't have their own rbac_entries, they just inherit from
# the network rbac entries
rbac_entries = orm.relationship(
rbac_db_models.NetworkRBAC, lazy='joined', uselist=True,
rbac_db_models.NetworkRBAC, lazy='subquery', uselist=True,
foreign_keys='Subnet.network_id',
primaryjoin='Subnet.network_id==NetworkRBAC.object_id')
api_collections = [attr.SUBNETS]
@ -236,13 +236,13 @@ class Network(standard_attr.HasStandardAttributes, model_base.BASEV2,
name = sa.Column(sa.String(attr.NAME_MAX_LEN))
ports = orm.relationship(Port, backref='networks')
subnets = orm.relationship(
Subnet, backref=orm.backref('networks', lazy='joined'),
lazy="joined")
Subnet, backref=orm.backref('networks', lazy='subquery'),
lazy="subquery")
status = sa.Column(sa.String(16))
admin_state_up = sa.Column(sa.Boolean)
vlan_transparent = sa.Column(sa.Boolean, nullable=True)
rbac_entries = orm.relationship(rbac_db_models.NetworkRBAC,
backref='network', lazy='joined',
backref='network', lazy='subquery',
cascade='all, delete, delete-orphan')
availability_zone_hints = sa.Column(sa.String(255))
dhcp_agents = orm.relationship(