Fetch specific columns rather than full ORM entities

Michael Bayer while analysing neutron process function call trace,
suggested to run queries against specific columns rather than full
ORM entities as it can help reduce load both at the DB level and
in the Python level since they are much faster to fetch as
non-ORM entities. In this patch we are trying that on simpler
queries to improve neutron performance.

Co-Authored-By: Joe Talerico <jtaleric@redhat.com>
Change-Id: I6a41e9487a4427f876442bbeeae61974e892225e
(cherry picked from commit 72ef0e7814)
This commit is contained in:
venkata anil 2018-08-16 17:57:17 +05:30 committed by Slawek Kaplonski
parent 8ccc9a8763
commit 02bd0ba84e
10 changed files with 26 additions and 25 deletions

View File

@ -606,16 +606,16 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
with db_api.context_manager.reader.using(context): with db_api.context_manager.reader.using(context):
# TODO(electrocucaracha): Look a solution for Join in OVO # TODO(electrocucaracha): Look a solution for Join in OVO
ipal = models_v2.IPAllocation ipal = models_v2.IPAllocation
alloc_qry = context.session.query(ipal) alloc_qry = context.session.query(ipal.port_id)
alloc_qry = alloc_qry.join("port", "routerport") alloc_qry = alloc_qry.join("port", "routerport")
gateway_ip = str(cur_subnet['gateway_ip']) gateway_ip = str(cur_subnet['gateway_ip'])
allocated = alloc_qry.filter( allocated = alloc_qry.filter(
ipal.ip_address == gateway_ip, ipal.ip_address == gateway_ip,
ipal.subnet_id == cur_subnet['id']).first() ipal.subnet_id == cur_subnet['id']).first()
if allocated and allocated['port_id']: if allocated and allocated.port_id:
raise n_exc.GatewayIpInUse( raise n_exc.GatewayIpInUse(
ip_address=gateway_ip, ip_address=gateway_ip,
port_id=allocated['port_id']) port_id=allocated.port_id)
if validators.is_attr_set(s.get('dns_nameservers')): if validators.is_attr_set(s.get('dns_nameservers')):
if len(s['dns_nameservers']) > cfg.CONF.max_dns_nameservers: if len(s['dns_nameservers']) > cfg.CONF.max_dns_nameservers:

View File

@ -124,10 +124,9 @@ class External_net_db_mixin(object):
# must make sure we do not have any external gateway ports # must make sure we do not have any external gateway ports
# (and thus, possible floating IPs) on this network before # (and thus, possible floating IPs) on this network before
# allow it to be update to external=False # allow it to be update to external=False
port = context.session.query(models_v2.Port).filter_by( if context.session.query(models_v2.Port.id).filter_by(
device_owner=constants.DEVICE_OWNER_ROUTER_GW, device_owner=constants.DEVICE_OWNER_ROUTER_GW,
network_id=net_data['id']).first() network_id=net_data['id']).first():
if port:
raise extnet_exc.ExternalNetworkInUse(net_id=net_id) raise extnet_exc.ExternalNetworkInUse(net_id=net_id)
net_obj.ExternalNetwork.delete_objects( net_obj.ExternalNetwork.delete_objects(
@ -172,12 +171,11 @@ class External_net_db_mixin(object):
if (object_type != 'network' or if (object_type != 'network' or
policy['action'] != 'access_as_external'): policy['action'] != 'access_as_external'):
return return
net_as_external = context.session.query(rbac_db.NetworkRBAC).filter(
rbac_db.NetworkRBAC.object_id == policy['object_id'],
rbac_db.NetworkRBAC.action == 'access_as_external').count()
# If the network still have rbac policies, we should not # If the network still have rbac policies, we should not
# update external attribute. # update external attribute.
if net_as_external: if context.session.query(rbac_db.NetworkRBAC.object_id).filter(
rbac_db.NetworkRBAC.object_id == policy['object_id'],
rbac_db.NetworkRBAC.action == 'access_as_external').count():
return return
net = self.get_network(context, policy['object_id']) net = self.get_network(context, policy['object_id'])
self._process_l3_update(context, net, self._process_l3_update(context, net,
@ -209,7 +207,7 @@ class External_net_db_mixin(object):
} }
# if there is a wildcard entry we can safely proceed without the # if there is a wildcard entry we can safely proceed without the
# router lookup because they will have access either way # router lookup because they will have access either way
if context.session.query(rbac_db.NetworkRBAC).filter( if context.session.query(rbac_db.NetworkRBAC.object_id).filter(
rbac.object_id == policy['object_id'], rbac.object_id == policy['object_id'],
rbac.action == 'access_as_external', rbac.action == 'access_as_external',
rbac.target_tenant == '*').count(): rbac.target_tenant == '*').count():

View File

@ -1875,12 +1875,12 @@ class L3RpcNotifierMixin(object):
return return
network_id = updated['network_id'] network_id = updated['network_id']
subnet_id = updated['id'] subnet_id = updated['id']
query = context.session.query(models_v2.Port).filter_by( query = context.session.query(models_v2.Port.device_id).filter_by(
network_id=network_id, network_id=network_id,
device_owner=DEVICE_OWNER_ROUTER_GW) device_owner=DEVICE_OWNER_ROUTER_GW)
query = query.join(models_v2.Port.fixed_ips).filter( query = query.join(models_v2.Port.fixed_ips).filter(
models_v2.IPAllocation.subnet_id == subnet_id) models_v2.IPAllocation.subnet_id == subnet_id)
router_ids = set(port['device_id'] for port in query) router_ids = set(port.device_id for port in query)
for router_id in router_ids: for router_id in router_ids:
l3plugin.notify_router_updated(context, router_id) l3plugin.notify_router_updated(context, router_id)

View File

@ -87,7 +87,7 @@ class PortBindingMixin(portbindings_base.PortBindingBaseMixin):
def get_port_host(self, context, port_id): def get_port_host(self, context, port_id):
with db_api.context_manager.reader.using(context): with db_api.context_manager.reader.using(context):
bind_port = ( bind_port = (
context.session.query(pmodels.PortBindingPort). context.session.query(pmodels.PortBindingPort.host).
filter_by(port_id=port_id). filter_by(port_id=port_id).
first() first()
) )

View File

@ -165,7 +165,8 @@ def _get_standard_attr_id(context, object_id, object_type):
"adding provisioning blocks for a new resource " "adding provisioning blocks for a new resource "
"you must call add_model_for_resource during " "you must call add_model_for_resource during "
"initialization for your type." % object_type) "initialization for your type." % object_type)
obj = (context.session.query(model).enable_eagerloads(False). obj = (context.session.query(model.standard_attr_id).
enable_eagerloads(False).
filter_by(id=object_id).first()) filter_by(id=object_id).first())
if not obj: if not obj:
# concurrent delete # concurrent delete

View File

@ -142,7 +142,7 @@ class RbacPluginMixin(common_db_mixin.CommonDbMixin):
if entry_id in self.object_type_cache: if entry_id in self.object_type_cache:
return self.object_type_cache[entry_id] return self.object_type_cache[entry_id]
for otype, model in models.get_type_model_map().items(): for otype, model in models.get_type_model_map().items():
if (context.session.query(model). if (context.session.query(model.id).
filter(model.id == entry_id).first()): filter(model.id == entry_id).first()):
self.object_type_cache[entry_id] = otype self.object_type_cache[entry_id] = otype
return otype return otype

View File

@ -75,7 +75,7 @@ class SubnetAllocator(driver.Pool):
def _get_allocated_cidrs(self): def _get_allocated_cidrs(self):
with db_api.context_manager.reader.using(self._context): with db_api.context_manager.reader.using(self._context):
query = self._context.session.query(models_v2.Subnet) query = self._context.session.query(models_v2.Subnet.cidr)
subnets = query.filter_by(subnetpool_id=self._subnetpool['id']) subnets = query.filter_by(subnetpool_id=self._subnetpool['id'])
return (x.cidr for x in subnets) return (x.cidr for x in subnets)
@ -97,7 +97,7 @@ class SubnetAllocator(driver.Pool):
subnetpool_id = self._subnetpool['id'] subnetpool_id = self._subnetpool['id']
tenant_id = self._subnetpool['tenant_id'] tenant_id = self._subnetpool['tenant_id']
with db_api.context_manager.reader.using(self._context): with db_api.context_manager.reader.using(self._context):
qry = self._context.session.query(models_v2.Subnet) qry = self._context.session.query(models_v2.Subnet.cidr)
allocations = qry.filter_by(subnetpool_id=subnetpool_id, allocations = qry.filter_by(subnetpool_id=subnetpool_id,
tenant_id=tenant_id) tenant_id=tenant_id)
value = 0 value = 0

View File

@ -214,7 +214,7 @@ def make_port_dict_with_security_groups(port, sec_groups):
def get_port_binding_host(context, port_id): def get_port_binding_host(context, port_id):
try: try:
with db_api.context_manager.reader.using(context): with db_api.context_manager.reader.using(context):
query = (context.session.query(models.PortBinding). query = (context.session.query(models.PortBinding.host).
filter(models.PortBinding.port_id.startswith(port_id))) filter(models.PortBinding.port_id.startswith(port_id)))
query = query.filter( query = query.filter(
models.PortBinding.status == n_const.ACTIVE).one() models.PortBinding.status == n_const.ACTIVE).one()
@ -233,7 +233,7 @@ def get_port_binding_host(context, port_id):
def generate_distributed_port_status(context, port_id): def generate_distributed_port_status(context, port_id):
# an OR'ed value of status assigned to parent port from the # an OR'ed value of status assigned to parent port from the
# distributedportbinding bucket # distributedportbinding bucket
query = context.session.query(models.DistributedPortBinding) query = context.session.query(models.DistributedPortBinding.status)
final_status = n_const.PORT_STATUS_BUILD final_status = n_const.PORT_STATUS_BUILD
for bind in query.filter(models.DistributedPortBinding.port_id == port_id): for bind in query.filter(models.DistributedPortBinding.port_id == port_id):
if bind.status == n_const.PORT_STATUS_ACTIVE: if bind.status == n_const.PORT_STATUS_ACTIVE:
@ -308,7 +308,7 @@ def get_port_db_objects(context, port_ids):
def is_dhcp_active_on_any_subnet(context, subnet_ids): def is_dhcp_active_on_any_subnet(context, subnet_ids):
if not subnet_ids: if not subnet_ids:
return False return False
return bool(context.session.query(models_v2.Subnet). return bool(context.session.query(models_v2.Subnet.id).
enable_eagerloads(False).filter_by(enable_dhcp=True). enable_eagerloads(False).filter_by(enable_dhcp=True).
filter(models_v2.Subnet.id.in_(subnet_ids)).count()) filter(models_v2.Subnet.id.in_(subnet_ids)).count())
@ -323,7 +323,7 @@ def _prevent_segment_delete_with_port_bound(resource, event, trigger,
with db_api.context_manager.reader.using(context): with db_api.context_manager.reader.using(context):
segment_id = segment['id'] segment_id = segment['id']
query = context.session.query(models_v2.Port) query = context.session.query(models_v2.Port.id)
query = query.join( query = query.join(
models.PortBindingLevel, models.PortBindingLevel,
models.PortBindingLevel.port_id == models_v2.Port.id) models.PortBindingLevel.port_id == models_v2.Port.id)

View File

@ -241,7 +241,8 @@ class TrackedResource(BaseResource):
LOG.debug(("Synchronizing usage tracker for tenant:%(tenant_id)s on " LOG.debug(("Synchronizing usage tracker for tenant:%(tenant_id)s on "
"resource:%(resource)s"), "resource:%(resource)s"),
{'tenant_id': tenant_id, 'resource': self.name}) {'tenant_id': tenant_id, 'resource': self.name})
in_use = context.session.query(self._model_class).filter_by( in_use = context.session.query(
self._model_class.tenant_id).filter_by(
tenant_id=tenant_id).count() tenant_id=tenant_id).count()
# Update quota usage # Update quota usage
return self._resync(context, tenant_id, in_use) return self._resync(context, tenant_id, in_use)
@ -270,7 +271,8 @@ class TrackedResource(BaseResource):
"%(tenant_id)s is out of sync, need to count used " "%(tenant_id)s is out of sync, need to count used "
"quota"), {'resource': self.name, "quota"), {'resource': self.name,
'tenant_id': tenant_id}) 'tenant_id': tenant_id})
in_use = context.session.query(self._model_class).filter_by( in_use = context.session.query(
self._model_class.tenant_id).filter_by(
tenant_id=tenant_id).count() tenant_id=tenant_id).count()
# Update quota usage, if requested (by default do not do that, as # Update quota usage, if requested (by default do not do that, as

View File

@ -56,7 +56,7 @@ class L3Scheduler(object):
def _router_has_binding(self, context, router_id, l3_agent_id): def _router_has_binding(self, context, router_id, l3_agent_id):
router_binding_model = rb_model.RouterL3AgentBinding router_binding_model = rb_model.RouterL3AgentBinding
query = context.session.query(router_binding_model) query = context.session.query(router_binding_model.router_id)
query = query.filter(router_binding_model.router_id == router_id, query = query.filter(router_binding_model.router_id == router_id,
router_binding_model.l3_agent_id == l3_agent_id) router_binding_model.l3_agent_id == l3_agent_id)