gitlab-org--gitlab-foss/app/controllers
Yorick Peterse 70985aa19b
Limit the number of pipelines to count
When displaying the project pipelines dashboard we display a few tabs
for different pipeline states. For every such tab we count the number of
pipelines that belong to it. For large projects such as GitLab CE this
means having to count over 80 000 rows, which can easily take between 70
and 100 milliseconds per query.

To improve this we apply a technique we already use for search results:
we limit the number of rows to count. The current limit is 1000, which
means that if more than 1000 rows are present for a state we will show
"1000+" instead of the exact number. The SQL queries used for this
perform much better than a regular COUNT, even when a project has a lot
of pipelines.

Prior to these changes we would end up running a query like this:

    SELECT COUNT(*)
    FROM ci_pipelines
    WHERE project_id = 13083
    AND status IN ('success', 'failed', 'canceled')

This would produce a plan along the lines of the following:

    Aggregate  (cost=3147.55..3147.56 rows=1 width=8) (actual time=501.413..501.413 rows=1 loops=1)
      Buffers: shared hit=17116 read=861 dirtied=2
      ->  Index Only Scan using index_ci_pipelines_on_project_id_and_ref_and_status_and_id on ci_pipelines  (cost=0.56..2984.14 rows=65364 width=0) (actual time=0.095..490.263 rows=80388 loops=1)
            Index Cond: (project_id = 13083)
            Filter: ((status)::text = ANY ('{success,failed,canceled}'::text[]))
            Rows Removed by Filter: 2894
            Heap Fetches: 353
            Buffers: shared hit=17116 read=861 dirtied=2
    Planning time: 1.409 ms
    Execution time: 501.519 ms

Using the LIMIT count technique we instead run the following query:

    SELECT COUNT(*)
    FROM (
        SELECT 1
        FROM ci_pipelines
        WHERE project_id = 13083
        AND status IN ('success', 'failed', 'canceled')
        LIMIT 1001
    ) for_count

This query produces the following plan:

    Aggregate  (cost=58.77..58.78 rows=1 width=8) (actual time=1.726..1.727 rows=1 loops=1)
      Buffers: shared hit=169 read=15
      ->  Limit  (cost=0.56..46.25 rows=1001 width=4) (actual time=0.164..1.570 rows=1001 loops=1)
            Buffers: shared hit=169 read=15
            ->  Index Only Scan using index_ci_pipelines_on_project_id_and_ref_and_status_and_id on ci_pipelines  (cost=0.56..2984.14 rows=65364 width=4) (actual time=0.162..1.426 rows=1001 loops=1)
                  Index Cond: (project_id = 13083)
                  Filter: ((status)::text = ANY ('{success,failed,canceled}'::text[]))
                  Rows Removed by Filter: 9
                  Heap Fetches: 10
                  Buffers: shared hit=169 read=15
    Planning time: 1.832 ms
    Execution time: 1.821 ms

While this query still uses a Filter for the "status" field the number
of rows that it may end up filtering (at most 1001) is small enough that
an additional index does not appear to be necessary at this time.

See https://gitlab.com/gitlab-org/gitlab-ce/issues/43132#note_68659234
for more information.
2018-05-17 13:52:59 +02:00
..
admin Fix Error 500 viewing admin page due to statement timeouts 2018-05-16 08:27:48 -07:00
boards Show issues of subgroups in group-level issue board 2018-04-05 14:58:49 -03:00
ci Make ci/lint page context aware: 2018-03-26 17:03:11 -06:00
concerns Resolve "Opening Project with invite but without accepting leads to 404 error page" 2018-05-17 09:19:47 +00:00
dashboard [Rails5] Add `safe_params` helper 2018-04-08 15:35:30 +11:00
explore Resolve "Display member role per project" 2017-12-07 09:11:41 +00:00
google_api Improve redirect uri state and fix all remaining tests 2017-10-06 16:14:14 +02:00
groups Add 2FA filter to group members page 2018-05-10 13:02:56 +03:00
import Align with EE 2018-05-09 18:19:44 +08:00
ldap Replace define_method with alias_method in Omniauth Controllers 2018-04-23 16:24:47 +01:00
oauth Port `read_cross_project` ability from EE 2018-02-22 17:11:36 +01:00
profiles Display and revoke active sessions 2018-05-02 08:08:16 +00:00
projects Limit the number of pipelines to count 2018-05-17 13:52:59 +02:00
sherlock
snippets Make sure NotesActions#noteable returns a Noteable in the update action 2017-11-16 15:12:23 +01:00
users Enforce terms acceptance before other requirements 2018-05-11 14:27:22 +02:00
abuse_reports_controller.rb
application_controller.rb Allow a user to sign out when on the terms page 2018-05-11 08:27:43 +02:00
autocomplete_controller.rb Use UserSerializer instead of `User.to_json` 2017-12-19 15:45:08 -06:00
confirmations_controller.rb Resolve "Opening Project with invite but without accepting leads to 404 error page" 2018-05-17 09:19:47 +00:00
dashboard_controller.rb Fixed dashboard filtering tests 2018-04-03 20:19:20 +02:00
groups_controller.rb Merge branch 'blackst0ne-rails5-add-safe-params-helper' into 'master' 2018-04-18 10:26:44 +00:00
health_check_controller.rb
health_controller.rb Add a gRPC health check to ensure Gitaly is up 2018-01-24 15:47:27 -08:00
help_controller.rb Enable RuboCop Style/RegexpLiteral 2018-02-01 02:06:07 +09:00
ide_controller.rb Move IDE to CE 2018-03-20 14:12:48 +00:00
invites_controller.rb Replace deprecated name_with_namespace with full_name in app and spec 2018-03-05 16:15:26 +02:00
jwt_controller.rb Handle limit for datetime attributes on MySQL 2018-04-06 22:28:44 -05:00
koding_controller.rb use Gitlab::UserSettings directly as a singleton instead of including/extending it 2018-02-02 18:39:55 +00:00
metrics_controller.rb Adds Rubocop rule for line break around conditionals 2018-01-11 16:34:01 +00:00
notification_settings_controller.rb
omniauth_callbacks_controller.rb Backport IdentityLinker#failed? from GroupSaml callback flow 2018-05-04 15:00:59 +01:00
passwords_controller.rb use Gitlab::UserSettings directly as a singleton instead of including/extending it 2018-02-02 18:39:55 +00:00
profiles_controller.rb Add confirmation modal to "Change username" 2018-04-06 09:36:22 +00:00
projects_controller.rb [Rails5] Add `safe_params` helper 2018-04-08 15:35:30 +11:00
registrations_controller.rb Resolve "Opening Project with invite but without accepting leads to 404 error page" 2018-05-17 09:19:47 +00:00
root_controller.rb 'Assigned Issues' and 'Assigned Merge Requests' as dashboard user choices 2018-03-27 12:16:12 +00:00
search_controller.rb Port `read_cross_project` ability from EE 2018-02-22 17:11:36 +01:00
sent_notifications_controller.rb Backport 5480-epic-notifications from EE 2018-05-07 12:58:47 -06:00
sessions_controller.rb Reuses `InternalRedirect` when possible 2018-05-04 13:54:43 +02:00
snippets_controller.rb embedded snippets support 2018-02-28 18:48:26 +05:30
uploads_controller.rb Revert "Merge branch '3867-port-to-ce' into 'master'" 2018-02-28 21:09:34 +01:00
user_callouts_controller.rb Refactor UserCalloutsController enum check 2018-02-05 14:48:28 +01:00
users_controller.rb [Rails5] Add `safe_params` helper 2018-04-08 15:35:30 +11:00