Merge lp:~wgrant/launchpad/bug-933853 into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 14822
Proposed branch: lp:~wgrant/launchpad/bug-933853
Merge into: lp:launchpad
Diff against target: 38 lines (+12/-8)
1 file modified
lib/lp/code/model/branchlookup.py (+12/-8)
To merge this branch: bzr merge lp:~wgrant/launchpad/bug-933853
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+93508@code.launchpad.net

Commit message

Tweak the query used by BranchLookup.getByUniqueName to obtain package branches so it uses a sensible plan.

Description of the change

When given ~ubuntu-branches as an owner, the package branch query in BranchLookup.getUniqueName does a full scan over ~ubuntu-branches's branches, taking about 1.5s -- it plans as if the person owns a single branch, which is of course not the case. stub and I tried various things, but nothing was better than just forcing it to assume there's only one DistroSeries by extracting that calculation out into a subselect, taking <1ms.

00:44:22 < stub> Night. I can't improve on what you have.
00:46:47 < wgrant> stub: Thanks. I might land that tomorrow, then.
00:47:19 < stub> http://paste.ubuntu.com/844395/ without the CTE

OLD
===

SELECT Branch.id FROM Branch JOIN Person ON Branch.owner = Person.id JOIN SourcePackageName ON Branch.sourcepackagename = SourcePackageName.id JOIN DistroSeries ON Branch.distroseries = DistroSeries.id JOIN Distribution ON DistroSeries.distribution = Distribution.id WHERE Person.name = E'ubuntu-branches' AND Distribution.name = E'ubuntu' AND DistroSeries.name = E'oneiric' AND SourcePackageName.name = E'dpkg' AND Branch.name = E'oneiric'

 Nested Loop (cost=0.00..355.15 rows=1 width=4) (actual time=1276.394..1363.889 rows=1 loops=1)
   -> Nested Loop (cost=0.00..354.80 rows=1 width=8) (actual time=0.321..1155.671 rows=21398 loops=1)
         Join Filter: (distroseries.distribution = distribution.id)
         -> Nested Loop (cost=0.00..348.35 rows=1 width=12) (actual time=0.285..643.485 rows=21398 loops=1)
               -> Nested Loop (cost=0.00..348.07 rows=1 width=12) (actual time=0.250..460.098 rows=21398 loops=1)
                     -> Index Scan using person__name__key on person (cost=0.00..8.47 rows=1 width=4) (actual time=0.107..0.109 rows=1 loops=1)
                           Index Cond: (name = 'ubuntu-branches'::text)
                     -> Index Scan using branch_owner_idx on branch (cost=0.00..339.52 rows=6 width=16) (actual time=0.136..411.200 rows=21398 loops=1)
                           Index Cond: (branch.owner = person.id)
                           Filter: (branch.name = 'oneiric'::text)
               -> Index Scan using distrorelease_pkey on distroseries (cost=0.00..0.27 rows=1 width=8) (actual time=0.004..0.005 rows=1 loops=21398)
                     Index Cond: (distroseries.id = branch.distroseries)
                     Filter: (distroseries.name = 'oneiric'::text)
         -> Seq Scan on distribution (cost=0.00..6.44 rows=1 width=4) (actual time=0.015..0.020 rows=1 loops=21398)
               Filter: (distribution.name = 'ubuntu'::text)
   -> Index Scan using sourcepackagename_pkey on sourcepackagename (cost=0.00..0.34 rows=1 width=4) (actual time=0.008..0.008 rows=0 loops=21398)
         Index Cond: (sourcepackagename.id = branch.sourcepackagename)
         Filter: (sourcepackagename.name = 'dpkg'::text)
 Total runtime: 1364.061 ms

NEW
===

SELECT Branch.id FROM Branch JOIN Person ON Branch.owner = Person.id JOIN SourcePackageName ON Branch.sourcepackagename = SourcePackageName.id WHERE Person.name = E'wgrant' AND Branch.distroseries = (SELECT DistroSeries.id FROM Distribution, DistroSeries WHERE DistroSeries.distribution = Distribution.id AND DistroSeries.name = E'oneiric' AND Distribution.name = E'ubuntu') AND SourcePackageName.name = E'dpkg' AND Branch.name = E'oneiric'

 Nested Loop (cost=10.07..34.71 rows=1 width=820) (actual time=0.171..0.180 rows=1 loops=1)
   InitPlan 1 (returns $0)
     -> Nested Loop (cost=0.00..10.07 rows=1 width=4) (actual time=0.066..0.088 rows=1 loops=1)
           Join Filter: (distribution.id = distroseries.distribution)
           -> Seq Scan on distribution (cost=0.00..6.44 rows=1 width=4) (actual time=0.035..0.042 rows=1 loops=1)
                 Filter: (name = 'ubuntu'::text)
           -> Seq Scan on distroseries (cost=0.00..3.60 rows=3 width=8) (actual time=0.010..0.037 rows=3 loops=1)
                 Filter: (distroseries.name = 'oneiric'::text)
   -> Nested Loop (cost=0.00..16.69 rows=1 width=820) (actual time=0.149..0.153 rows=1 loops=1)
         -> Index Scan using sourcepackagename_name_key on sourcepackagename (cost=0.00..8.27 rows=1 width=4) (actual time=0.032..0.034 rows=1 loops=1)
               Index Cond: (name = 'dpkg'::text)
         -> Index Scan using branch__ds__spn__owner__name__key on branch (cost=0.00..8.40 rows=1 width=820) (actual time=0.018..0.019 rows=1 loops=1)
               Index Cond: ((branch.distroseries = $0) AND (branch.sourcepackagename = sourcepackagename.id) AND (branch.name = 'oneiric'::text))
   -> Index Scan using person_pkey on person (cost=0.00..7.94 rows=1 width=4) (actual time=0.018..0.020 rows=1 loops=1)
         Index Cond: (person.id = branch.owner)
         Filter: (person.name = 'ubuntu-branches'::text)
 Total runtime: 0.381 ms

To post a comment you must log in.
Revision history for this message
Ian Booth (wallyworld) wrote :

Very nice.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/model/branchlookup.py'
2--- lib/lp/code/model/branchlookup.py 2012-01-01 02:58:52 +0000
3+++ lib/lp/code/model/branchlookup.py 2012-02-16 23:19:52 +0000
4@@ -14,7 +14,11 @@
5 URI,
6 )
7 from sqlobject import SQLObjectNotFound
8-from storm.expr import Join
9+from storm.expr import (
10+ And,
11+ Join,
12+ Select,
13+ )
14 from zope.component import (
15 adapts,
16 getUtility,
17@@ -391,14 +395,14 @@
18 Branch,
19 Join(Person, Branch.owner == Person.id),
20 Join(SourcePackageName,
21- Branch.sourcepackagename == SourcePackageName.id),
22- Join(DistroSeries,
23- Branch.distroseries == DistroSeries.id),
24- Join(Distribution,
25- DistroSeries.distribution == Distribution.id)]
26+ Branch.sourcepackagename == SourcePackageName.id)]
27 result = store.using(*origin).find(
28- Branch, Person.name == owner, Distribution.name == distribution,
29- DistroSeries.name == distroseries,
30+ Branch, Person.name == owner,
31+ Branch.distroseriesID == Select(
32+ DistroSeries.id, And(
33+ DistroSeries.distribution == Distribution.id,
34+ DistroSeries.name == distroseries,
35+ Distribution.name == distribution)),
36 SourcePackageName.name == sourcepackagename,
37 Branch.name == branch)
38 branch = result.one()