Use a UNION ALL for getting merge request notes
This MR changes MergeRequest#related_notes
so that it uses a UNION ALL instead of an OR, resulting in a better query plan.
This fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/38508 since the new query consistently runs in about 2-3 ms.
TODO
-
Deploy this somehow to GitLab.com (temporarily) so we can get better insight on the impact across the board -
Test this new query with a lot of commit IDs to see how this affects performance -
Re-run EXPLAIN ANALYZE
but withBUFFERS
enabled
SQL Info
Per https://gitlab.com/gitlab-org/gitlab-ce/issues/38508#note_41779221 the new SQL query is:
SELECT notes.*
FROM (
SELECT notes.*
FROM notes
WHERE notes.project_id = 13083
AND notes.noteable_id = 3985770
AND notes.noteable_type = 'MergeRequest'
UNION ALL
SELECT notes.*
FROM notes
WHERE notes.project_id IN (13083, 13083)
AND notes.noteable_type = 'Commit'
AND notes.commit_id IN ('aac1de46c9be659b74da12f704412f38292974db', '0395c47193b3bbf6b4f060f28c9f632580313a35')
) notes;
Which on GitLab.com produces the following plan:
Append (cost=0.56..2566.66 rows=6 width=2390) (actual time=0.021..0.990 rows=312 loops=1)
-> Index Scan using index_notes_on_noteable_id_and_noteable_type on notes (cost=0.56..38.23 rows=1 width=2390) (actual time=0.020..0.791 rows=310 loops=1)
Index Cond: ((noteable_id = 3985770) AND ((noteable_type)::text = 'MergeRequest'::text))
Filter: (project_id = 13083)
-> Index Scan using index_notes_on_commit_id on notes notes_1 (cost=0.56..2528.38 rows=5 width=2390) (actual time=0.021..0.047 rows=2 loops=1)
Index Cond: ((commit_id)::text = ANY ('{aac1de46c9be659b74da12f704412f38292974db,0395c47193b3bbf6b4f060f28c9f632580313a35}'::text[]))
Filter: ((project_id = ANY ('{13083,13083}'::integer[])) AND ((noteable_type)::text = 'Commit'::text))
Planning time: 0.477 ms
Execution time: 1.120 ms
Compared to the old plan:
Bitmap Heap Scan on notes (cost=1570.26..1616.70 rows=3 width=2390) (actual time=2.368..6.096 rows=312 loops=1)
Recheck Cond: (((noteable_id = 3985770) AND ((noteable_type)::text = 'MergeRequest'::text)) OR (((commit_id)::text = ANY ('{aac1de46c9be659b74da12f704412f38292974db,0395c47193b3bbf6b4f060f28c9f632580313a35}'::text[])) AND (project_id = 13083) AND ((noteable_type)::text = 'Commit'::text)))
Filter: (project_id = 13083)
Heap Blocks: exact=277
-> BitmapOr (cost=1570.26..1570.26 rows=23 width=0) (actual time=2.310..2.310 rows=0 loops=1)
-> Bitmap Index Scan on index_notes_on_noteable_id_and_noteable_type (cost=0.00..2.76 rows=20 width=0) (actual time=0.176..0.176 rows=310 loops=1)
Index Cond: ((noteable_id = 3985770) AND ((noteable_type)::text = 'MergeRequest'::text))
-> BitmapAnd (cost=1567.25..1567.25 rows=2 width=0) (actual time=2.132..2.132 rows=0 loops=1)
-> Bitmap Index Scan on index_notes_on_commit_id (cost=0.00..30.55 rows=1257 width=0) (actual time=0.095..0.095 rows=2 loops=1)
Index Cond: ((commit_id)::text = ANY ('{aac1de46c9be659b74da12f704412f38292974db,0395c47193b3bbf6b4f060f28c9f632580313a35}'::text[]))
-> Bitmap Index Scan on index_notes_on_project_id_and_noteable_type (cost=0.00..1536.45 rows=61189 width=0) (actual time=1.987..1.987 rows=6554 loops=1)
Index Cond: ((project_id = 13083) AND ((noteable_type)::text = 'Commit'::text))
Planning time: 2.210 ms
Execution time: 6.257 ms
Database Checklist
When adding or modifying queries to improve performance:
-
Included the raw SQL queries of the relevant queries -
Included the output of EXPLAIN ANALYZE
and execution timings of the relevant queries -
Added tests for the relevant changes
General Checklist
-
Changelog entry added, if necessary -
Tests added for this feature/bug - Review
-
Has been reviewed by Backend -
Has been reviewed by Database
-
-
Conform by the merge request performance guides -
Conform by the style guides -
Squashed related commits together
Edited by yorickpeterse-staging