mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-13 01:44:08 -04:00
Avoid doing a single SQL query per overlapping area
To count phones in a custom polygon we need to work out the percentage of overlap with each known area. This means we need to get each known area from the database to compare it. At the moment we do this by running: - one SQLite query to get the details of all matching areas - a loop, which performs one SQLite query *per area* to get the polygons This commit reduces the number of SQLite queries to one, which uses a `JOIN` to get both the details of the areas and their polygons. This gives a speed increase of about 25% for a big area like Lincolnshire.
This commit is contained in:
@@ -86,6 +86,12 @@ class BroadcastArea(BaseBroadcastArea, SortableMixin):
|
||||
def __init__(self, row):
|
||||
self.id, self.name, self._count_of_phones, self.library_id = row
|
||||
|
||||
@classmethod
|
||||
def from_row_with_simple_polygons(cls, row):
|
||||
instance = cls(row[:4])
|
||||
instance.simple_polygons = Polygons(row[4])
|
||||
return instance
|
||||
|
||||
@cached_property
|
||||
def polygons(self):
|
||||
return Polygons(
|
||||
@@ -162,7 +168,7 @@ class CustomBroadcastArea(BaseBroadcastArea):
|
||||
def overlapping_areas(self):
|
||||
if not self.polygons:
|
||||
return []
|
||||
return broadcast_area_libraries.get_areas([
|
||||
return broadcast_area_libraries.get_areas_with_simple_polygons([
|
||||
overlap.data for overlap in rtree_index.query(
|
||||
Rect(*self.polygons.bounds)
|
||||
)
|
||||
@@ -229,5 +235,12 @@ class BroadcastAreaLibraries(SerialisedModelCollection, GetItemByIdMixin):
|
||||
areas = BroadcastAreasRepository().get_areas(area_ids)
|
||||
return [BroadcastArea(area) for area in areas]
|
||||
|
||||
def get_areas_with_simple_polygons(self, *area_ids):
|
||||
if len(area_ids) == 1 and isinstance(area_ids[0], list):
|
||||
area_ids = area_ids[0]
|
||||
|
||||
areas = BroadcastAreasRepository().get_areas_with_simple_polygons(area_ids)
|
||||
return [BroadcastArea.from_row_with_simple_polygons(area) for area in areas]
|
||||
|
||||
|
||||
broadcast_area_libraries = BroadcastAreaLibraries()
|
||||
|
||||
@@ -141,6 +141,23 @@ class BroadcastAreasRepository(object):
|
||||
|
||||
return areas
|
||||
|
||||
def get_areas_with_simple_polygons(self, area_ids):
|
||||
q = """
|
||||
SELECT broadcast_areas.id, name, count_of_phones, broadcast_area_library_id, simple_polygons
|
||||
FROM broadcast_areas
|
||||
JOIN broadcast_area_polygons on broadcast_area_polygons.id = broadcast_areas.id
|
||||
WHERE broadcast_areas.id IN ({})
|
||||
""".format(("?," * len(area_ids))[:-1])
|
||||
|
||||
results = self.query(q, *area_ids)
|
||||
|
||||
areas = [
|
||||
(row[0], row[1], row[2], row[3], json.loads(row[4]))
|
||||
for row in results
|
||||
]
|
||||
|
||||
return areas
|
||||
|
||||
def get_all_areas_for_library(self, library_id):
|
||||
is_multi_tier_library = self.query("""
|
||||
SELECT exists(
|
||||
|
||||
Reference in New Issue
Block a user