Merge lp:~cjwatson/launchpad/optimise-spec-search into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18569
Proposed branch: lp:~cjwatson/launchpad/optimise-spec-search
Merge into: lp:launchpad
Diff against target: 44 lines (+16/-2)
1 file modified
lib/lp/blueprints/model/specificationsearch.py (+16/-2)
To merge this branch: bzr merge lp:~cjwatson/launchpad/optimise-spec-search
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+338425@code.launchpad.net

Commit message

Move base clauses for specification searches into a CTE to avoid slow sequential scans.

Description of the change

This should fix timeouts on e.g. Person:+specs; EXPLAIN (ANALYZE, BUFFERS) of the relevant slow query on dogfood goes from about 27s to under 300ms with this change.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/blueprints/model/specificationsearch.py'
2--- lib/lp/blueprints/model/specificationsearch.py 2015-10-26 14:54:43 +0000
3+++ lib/lp/blueprints/model/specificationsearch.py 2018-02-21 12:52:03 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2013 Canonical Ltd. This software is licensed under the
6+# Copyright 2013-2018 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Helper methods to search specifications."""
10@@ -16,11 +16,14 @@
11 from storm.expr import (
12 And,
13 Coalesce,
14+ Column,
15 Join,
16 LeftJoin,
17 Not,
18 Or,
19 Select,
20+ Table,
21+ With,
22 )
23 from storm.locals import (
24 Desc,
25@@ -80,7 +83,18 @@
26
27 if not tables:
28 tables = [Specification]
29- clauses = base_clauses
30+ clauses = []
31+ # If there are any base clauses, they typically have good selectivity,
32+ # so use a CTE to force PostgreSQL to calculate them up-front rather
33+ # than doing a sequential scan for visible specifications.
34+ if base_clauses:
35+ RelevantSpecification = Table('RelevantSpecification')
36+ relevant_specification_cte = With(
37+ RelevantSpecification.name,
38+ Select(Specification.id, And(base_clauses)))
39+ store = store.with_(relevant_specification_cte)
40+ clauses.append(Specification.id.is_in(
41+ Select(Column('id', RelevantSpecification))))
42 product_table, product_clauses = get_specification_active_product_filter(
43 context)
44 tables.extend(product_table)