Merge lp:~james-w/python-oops-tools/recent-oopses into lp:python-oops-tools
Status: | Merged |
---|---|
Approved by: | James Westby |
Approved revision: | no longer in the source branch. |
Merged at revision: | 51 |
Proposed branch: | lp:~james-w/python-oops-tools/recent-oopses |
Merge into: | lp:python-oops-tools |
Diff against target: |
151 lines (+114/-2) 3 files modified
src/oopstools/oops/migrations/0023_add_prefix_date_index.py (+92/-0) src/oopstools/oops/test/test_report.py (+19/-1) src/oopstools/oops/views.py (+3/-1) |
To merge this branch: | bzr merge lp:~james-w/python-oops-tools/recent-oopses |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Richard Harding (community) | Approve | ||
Review via email: mp+138356@code.launchpad.net |
Commit message
Improve the query performance of the recent oopses view.
Firstly the planner was picking a difficult plan because of the join, but
we expect few prefixes per-report, so getting the prefix ids first, then
using a simple IN rather than a join leads to an easier plan.
Once the easier plan is in use the indexes still aren't that helpful, as
it chooses the index on 'date', but it still has to filter based on the
prefix, so we add an index on (prefix_id, date) so that it can select the
right rows as quickly as possible.
Lastly lazy evaluation was causing 50 queries for the 'oopsinfestation'
info, so we use select_related() to include that in the main query.
There's a test that we do 1 query for the last point, but no test for
the speed of the query.
Description of the change
Hi,
The recent oops views are performing terribly, because the production
data makes the query really slow.
Firstly, lazy evaluation means that we are doing 50 queries for the
oopsinfestation info at render time. I've added a select_related
to avoid that.
Secondly, the query is just currently slow.
We start of with a plan like: (using some data generated locally rather
than the real data, but the plan matches)
Limit (cost=5.37..537.81 rows=50 width=2017) (actual time=0.212..145.954 rows=50 loops=1)
-> Nested Loop (cost=5.
-> Nested Loop (cost=5.
Join Filter: (oops_prefix.id = oops_oops.
-> Index Scan Backward using oops_oops_date on oops_oops (cost=0.
-> Materialize (cost=5.37..15.98 rows=1 width=8) (actual time=0.000..0.000 rows=1 loops=216002)
-> Index Scan using oops_infestatio
Total runtime: 146.193 ms
This is doing a join that is making the plan fairly costly, but we are typically only going to
be joining for one or a few rows of the other table. If we instead issue a query for the
few rows, the use a simple IN for the foreign key relation we can get a much simpler
query (again with local data):
Limit (cost=0.00..991.15 rows=50 width=2017) (actual time=0.061..65.703 rows=50 loops=1)
-> Nested Loop (cost=0.
-> Index Scan Backward using oops_oops_date on oops_oops (cost=0.
-> Index Scan using oops_infestatio
Total runtime: 65.784 ms
which has a worse estimate, but better actual. I've tested this version of the query on production,
and it has the same characteristic (and drops the actual from 0.158..31828.728 to 80.303..459.145).
Next we see that the index scan on oops_oops_date is the majority of the time, and it has
a filter, so we try adding an index that also includes the filter criteria:
Limit (cost=0.00..342.44 rows=50 width=2017) (actual time=0.085..0.531 rows=50 loops=1)
-> Nested Loop (cost=0.
-> Index Scan Backward using oops_oops_
-> Index Scan using oops_infestatio
Total runtime: 0.614 ms
This is much better, with the estimate now being lower than the starting query, and
the actual being far far quicker. I can't test this on production, so it may not
have the same effect there, but I think it's worth a try.
Overall I think these changes should significantly improve the render time on production,
and if it isn't a sufficient improvement we can see where the problem areas remain.
This is my first time trying query optimisation, so I may have made some glaring errors,
please point them out if I have.
Thanks,
James