Avoid unnecessary joins in InstanceGroup.get_hosts

The InstanceList.get_by_filters query is joining on
info_cache, security_groups, metadata and system_metadata
because of how instance_get_all_by_filters_sort in the DB API
works if columns_to_join (expected_attrs) is None. The get_hosts
method only cares about the instance.host value of its members
so those joins are unnecessarily expensive.

This change simply passes expected_attrs=[] to get_by_filters
to avoid the joins. A follow up change can further optimize this
code by adding a new query method to just get the host values
for a list of instance uuids, so a TODO is left in place for that.
Note that a new query method would need to be remotable and thus
not something we can backport.

Change-Id: I53d4b38d12404a1641f667c537404effa837a83d
Partial-Bug: #1830234
(cherry picked from commit 15ccf2ddfb)
This commit is contained in:
Matt Riedemann 2019-05-23 11:14:55 -04:00
parent 105e6238dd
commit 74e66fe8d4
2 changed files with 12 additions and 3 deletions

View File

@ -497,8 +497,15 @@ class InstanceGroup(base.NovaPersistentObject, base.NovaObject,
if exclude:
filter_uuids = set(filter_uuids) - set(exclude)
filters = {'uuid': filter_uuids, 'deleted': False}
# Pass expected_attrs=[] to avoid unnecessary joins.
# TODO(mriedem): This is pretty inefficient since all we care about
# are the hosts. We could optimize this with a single-purpose SQL query
# like:
# SELECT host FROM instances WHERE deleted=0 AND host IS NOT NULL
# AND uuid IN ($filter_uuids) GROUP BY host;
instances = objects.InstanceList.get_by_filters(self._context,
filters=filters)
filters=filters,
expected_attrs=[])
return list(set([instance.host for instance in instances
if instance.host]))

View File

@ -280,7 +280,8 @@ class _TestInstanceGroupObject(object):
'deleted': False
}
mock_il_get.assert_called_once_with(self.context,
filters=expected_filters)
filters=expected_filters,
expected_attrs=[])
self.assertEqual(2, len(hosts))
self.assertIn('host1', hosts)
self.assertIn('host2', hosts)
@ -293,7 +294,8 @@ class _TestInstanceGroupObject(object):
'deleted': False
}
mock_il_get.assert_called_once_with(self.context,
filters=expected_filters)
filters=expected_filters,
expected_attrs=[])
def test_obj_make_compatible(self):
obj = objects.InstanceGroup(self.context, **_INST_GROUP_OBJ_VALS)