Skip to content

Commit 3007158

Browse files
authored
speed up slow query (#1176)
1 parent 7058f31 commit 3007158

File tree

2 files changed

+42
-31
lines changed

2 files changed

+42
-31
lines changed

store/backend/neurostore/resources/base.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,26 +160,29 @@ def update_base_studies(self, base_studies):
160160
if not base_studies:
161161
return
162162

163-
# Subquery for new_has_coordinates
164-
new_has_coordinates_subquery = (
165-
sa.select(sa.func.count(Point.id) > 0)
166-
.select_from(Study)
167-
.join(Analysis, Analysis.study_id == Study.id)
168-
.join(Point, Point.analysis_id == Analysis.id)
163+
studies_for_base_study = (
164+
sa.select(Study.id)
169165
.where(Study.base_study_id == BaseStudy.id)
170166
.correlate(BaseStudy)
171167
.scalar_subquery()
172168
)
173169

174-
# Subquery for new_has_images
170+
# Subquery for new_has_coordinates using EXISTS for early exit
171+
new_has_coordinates_subquery = (
172+
sa.select(sa.literal(1))
173+
.select_from(Analysis)
174+
.join(Point, Point.analysis_id == Analysis.id)
175+
.where(Analysis.study_id.in_(studies_for_base_study))
176+
.exists()
177+
)
178+
179+
# Subquery for new_has_images using EXISTS for early exit
175180
new_has_images_subquery = (
176-
sa.select(sa.func.count(Image.id) > 0)
177-
.select_from(Study)
178-
.join(Analysis, Analysis.study_id == Study.id)
181+
sa.select(sa.literal(1))
182+
.select_from(Analysis)
179183
.join(Image, Image.analysis_id == Analysis.id)
180-
.where(Study.base_study_id == BaseStudy.id)
181-
.correlate(BaseStudy)
182-
.scalar_subquery()
184+
.where(Analysis.study_id.in_(studies_for_base_study))
185+
.exists()
183186
)
184187

185188
# Main query

store/backend/neurostore/resources/data.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -722,25 +722,33 @@ def view_search(self, q, args):
722722
radius = float(radius)
723723
except Exception:
724724
abort_validation("Spatial parameters must be numeric.")
725-
# Join BaseStudy -> Study -> Analysis -> Point
726-
q = q.join(Study, Study.base_study_id == self._model.id)
727-
q = q.join(Analysis, Analysis.study_id == Study.id)
728-
q = q.join(Point, Point.analysis_id == Analysis.id)
729-
# Box filter first, then Euclidean distance
730-
q = q.filter(
731-
Point.x <= x + radius,
732-
Point.x >= x - radius,
733-
Point.y <= y + radius,
734-
Point.y >= y - radius,
735-
Point.z <= z + radius,
736-
Point.z >= z - radius,
737-
(Point.x - x) * (Point.x - x)
738-
+ (Point.y - y) * (Point.y - y)
739-
+ (Point.z - z) * (Point.z - z)
740-
<= radius * radius,
725+
# Use EXISTS so we do not duplicate base studies when filtering by spatial criteria
726+
spatial_point = aliased(Point)
727+
spatial_analysis = aliased(Analysis)
728+
spatial_study = aliased(Study)
729+
730+
spatial_filter = (
731+
sa.select(sa.literal(True))
732+
.select_from(spatial_study)
733+
.join(spatial_analysis, spatial_analysis.study_id == spatial_study.id)
734+
.join(spatial_point, spatial_point.analysis_id == spatial_analysis.id)
735+
.where(
736+
spatial_study.base_study_id == self._model.id,
737+
spatial_point.x <= x + radius,
738+
spatial_point.x >= x - radius,
739+
spatial_point.y <= y + radius,
740+
spatial_point.y >= y - radius,
741+
spatial_point.z <= z + radius,
742+
spatial_point.z >= z - radius,
743+
(spatial_point.x - x) * (spatial_point.x - x)
744+
+ (spatial_point.y - y) * (spatial_point.y - y)
745+
+ (spatial_point.z - z) * (spatial_point.z - z)
746+
<= radius * radius,
747+
)
748+
.correlate(self._model)
749+
.exists()
741750
)
742-
# Only return distinct base studies
743-
q = q.distinct()
751+
q = q.filter(spatial_filter)
744752
elif any(v is not None for v in [x, y, z, radius]):
745753
abort_validation("Spatial query requires x, y, z, and radius together.")
746754

0 commit comments

Comments
 (0)