Skip to content

Add missing issue due date filters

Lee Tickett requested to merge add-missing-issue-due-date-filters into master

What does this MR do and why?

Adds any, today, and tomorrow issue due_date filters to API.

MR created during pairing session with @espadav8 - thanks Andrew 💪

DB

There are identical and more complex plans for existing queries so we should be good 👌

Details for searching all issues in a project
SELECT COUNT(*) FROM "issues" WHERE "issues"."project_id" = 6 AND "issues"."due_date" = '2022-01-22'

 Aggregate  (cost=3.45..3.46 rows=1 width=8) (actual time=0.041..0.041 rows=1 loops=1)
   Buffers: shared hit=3
   I/O Timings: read=0.000 write=0.000
   ->  Index Only Scan using idx_issues_on_project_id_and_due_date_and_id_and_state_id on public.issues  (cost=0.43..3.45 rows=1 width=0) (actual time=0.036..0.037 rows=0 loops=1)
         Index Cond: ((issues.project_id = 6) AND (issues.due_date = '2022-01-22'::date))
         Heap Fetches: 0
         Buffers: shared hit=3
         I/O Timings: read=0.000 write=0.000

cold:
Time: 1.922 ms
  - planning: 0.343 ms
  - execution: 1.579 ms
    - I/O read: 1.466 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 1 (~8.00 KiB) from the buffer pool
  - reads: 2 (~16.00 KiB) from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

warm:
Time: 0.371 ms
  - planning: 0.290 ms
  - execution: 0.081 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 3 (~24.00 KiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

SELECT "issues".* FROM "issues" WHERE "issues"."project_id" = 6 AND "issues"."due_date" = '2022-01-22' ORDER BY "issues"."created_at" DESC, "issues"."id" DESC LIMIT 20 OFFSET 0

 Limit  (cost=3.46..3.46 rows=1 width=1417) (actual time=0.042..0.043 rows=0 loops=1)
   Buffers: shared hit=9
   I/O Timings: read=0.000 write=0.000
   ->  Sort  (cost=3.46..3.46 rows=1 width=1417) (actual time=0.040..0.041 rows=0 loops=1)
         Sort Key: issues.created_at DESC, issues.id DESC
         Sort Method: quicksort  Memory: 25kB
         Buffers: shared hit=9
         I/O Timings: read=0.000 write=0.000
         ->  Index Scan using idx_issues_on_project_id_and_due_date_and_id_and_state_id on public.issues  (cost=0.43..3.45 rows=1 width=1417) (actual time=0.020..0.020 rows=0 loops=1)
               Index Cond: ((issues.project_id = 6) AND (issues.due_date = '2022-01-22'::date))
               Buffers: shared hit=3
               I/O Timings: read=0.000 write=0.000


Time: 2.752 ms
  - planning: 2.664 ms
  - execution: 0.088 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 9 (~72.00 KiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0
Details for searching all issues in a group
explain SELECT COUNT(*) FROM "issues" INNER JOIN "projects" ON "projects"."id" = "issues"."project_id" LEFT JOIN project_features ON projects.id = project_features.project_id WHERE "projects"."namespace_id" IN (WITH RECURSIVE "base_and_descendants" AS ((SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 9970)
UNION
(SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces", "base_and_descendants" WHERE "namespaces"."type" = 'Group' AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT "namespaces"."id" FROM "base_and_descendants" AS "namespaces") AND (EXISTS (SELECT 1 FROM "project_authorizations" WHERE "project_authorizations"."user_id" = 1 AND (project_authorizations.project_id = projects.id)) OR projects.visibility_level IN (0,10,20)) AND ("project_features"."issues_access_level" > 0 OR "project_features"."issues_access_level" IS NULL) AND "projects"."archived" = FALSE AND "issues"."due_date" = '2022-01-22'

 Aggregate  (cost=24916.79..24916.80 rows=1 width=8) (actual time=26.771..26.778 rows=1 loops=1)
   Buffers: shared hit=17208
   I/O Timings: read=0.000 write=0.000
   ->  Nested Loop Left Join  (cost=1553.97..24916.79 rows=1 width=0) (actual time=16.673..26.770 rows=4 loops=1)
         Filter: ((project_features.issues_access_level > 0) OR (project_features.issues_access_level IS NULL))
         Rows Removed by Filter: 0
         Buffers: shared hit=17208
         I/O Timings: read=0.000 write=0.000
         ->  Nested Loop  (cost=1553.54..24916.29 rows=1 width=4) (actual time=16.648..26.714 rows=4 loops=1)
               Buffers: shared hit=17192
               I/O Timings: read=0.000 write=0.000
               ->  Nested Loop  (cost=1553.11..23099.06 rows=3883 width=4) (actual time=3.284..20.179 rows=1641 loops=1)
                     Buffers: shared hit=12264
                     I/O Timings: read=0.000 write=0.000
                     ->  HashAggregate  (cost=1552.54..1554.54 rows=200 width=4) (actual time=3.202..3.290 rows=292 loops=1)
                           Group Key: namespaces.id
                           Buffers: shared hit=1519
                           I/O Timings: read=0.000 write=0.000
                           ->  CTE Scan on base_and_descendants namespaces  (cost=1546.01..1550.03 rows=201 width=4) (actual time=0.047..3.088 rows=292 loops=1)
                                 Buffers: shared hit=1519
                                 I/O Timings: read=0.000 write=0.000
                                 CTE base_and_descendants
                                   ->  Recursive Union  (cost=0.43..1546.01 rows=201 width=358) (actual time=0.045..2.645 rows=292 loops=1)
                                         Buffers: shared hit=1519
                                         I/O Timings: read=0.000 write=0.000
                                         ->  Index Scan using namespaces_pkey on public.namespaces namespaces_1  (cost=0.43..3.46 rows=1 width=358) (actual time=0.037..0.039 rows=1 loops=1)
                                               Index Cond: (namespaces_1.id = 9970)
                                               Filter: ((namespaces_1.type)::text = 'Group'::text)
                                               Rows Removed by Filter: 0
                                               Buffers: shared hit=4
                                               I/O Timings: read=0.000 write=0.000
                                         ->  Nested Loop  (cost=0.56..153.85 rows=20 width=358) (actual time=0.019..0.323 rows=48 loops=6)
                                               Buffers: shared hit=1515
                                               I/O Timings: read=0.000 write=0.000
                                               ->  WorkTable Scan on base_and_descendants  (cost=0.00..0.20 rows=10 width=4) (actual time=0.001..0.005 rows=49 loops=6)
                                                     I/O Timings: read=0.000 write=0.000
                                               ->  Index Scan using index_namespaces_on_parent_id_and_id on public.namespaces namespaces_2  (cost=0.56..15.35 rows=2 width=358) (actual time=0.004..0.006 rows=1 loops=292)
                                                     Index Cond: (namespaces_2.parent_id = base_and_descendants.id)
                                                     Filter: ((namespaces_2.type)::text = 'Group'::text)
                                                     Rows Removed by Filter: 0
                                                     Buffers: shared hit=1515
                                                     I/O Timings: read=0.000 write=0.000
                     ->  Index Scan using index_projects_on_namespace_id_and_id on public.projects  (cost=0.56..107.53 rows=19 width=8) (actual time=0.013..0.057 rows=6 loops=292)
                           Index Cond: (projects.namespace_id = namespaces.id)
                           Filter: ((NOT projects.archived) AND ((alternatives: SubPlan 1 or hashed SubPlan 2) OR (projects.visibility_level = ANY ('{0,10,20}'::integer[]))))
                           Rows Removed by Filter: 0
                           Buffers: shared hit=10745
                           I/O Timings: read=0.000 write=0.000
                           SubPlan 1
                             ->  Index Only Scan using index_project_authorizations_on_project_id_user_id on public.project_authorizations  (cost=0.57..3.59 rows=1 width=0) (actual time=0.007..0.007 rows=1 loops=1641)
                                   Index Cond: ((project_authorizations.project_id = projects.id) AND (project_authorizations.user_id = 1))
                                   Heap Fetches: 164
                                   Buffers: shared hit=7812
                                   I/O Timings: read=0.000 write=0.000
                           SubPlan 2
                             ->  Index Only Scan using project_authorizations_pkey on public.project_authorizations project_authorizations_1  (cost=0.57..228.48 rows=6448 width=4) (actual time=0.000..0.000 rows=0 loops=0)
                                   Index Cond: (project_authorizations_1.user_id = 1)
                                   Heap Fetches: 0
                                   I/O Timings: read=0.000 write=0.000
               ->  Index Only Scan using idx_issues_on_project_id_and_due_date_and_id_and_state_id on public.issues  (cost=0.43..0.46 rows=1 width=4) (actual time=0.004..0.004 rows=0 loops=1641)
                     Index Cond: ((issues.project_id = projects.id) AND (issues.due_date = '2022-01-22'::date))
                     Heap Fetches: 1
                     Buffers: shared hit=4928
                     I/O Timings: read=0.000 write=0.000
         ->  Index Scan using index_project_features_on_project_id on public.project_features  (cost=0.44..0.48 rows=1 width=8) (actual time=0.012..0.012 rows=1 loops=4)
               Index Cond: (project_features.project_id = projects.id)
               Buffers: shared hit=16
               I/O Timings: read=0.000 write=0.000


cold:
Time: 6.065 s
  - planning: 2.207 ms
  - execution: 6.063 s
    - I/O read: 6.000 s
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 10168 (~79.40 MiB) from the buffer pool
  - reads: 7051 (~55.10 MiB) from the OS file cache, including disk I/O
  - dirtied: 105 (~840.00 KiB)
  - writes: 0

warm:
Time: 29.307 ms
  - planning: 2.215 ms
  - execution: 27.092 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 17208 (~134.40 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

SELECT "issues".* FROM "issues" INNER JOIN "projects" ON "projects"."id" = "issues"."project_id" LEFT JOIN project_features ON projects.id = project_features.project_id WHERE "projects"."namespace_id" IN (WITH RECURSIVE "base_and_descendants" AS ((SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 26)
UNION
(SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces", "base_and_descendants" WHERE "namespaces"."type" = 'Group' AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT "namespaces"."id" FROM "base_and_descendants" AS "namespaces") AND (EXISTS (SELECT 1 FROM "project_authorizations" WHERE "project_authorizations"."user_id" = 1 AND (project_authorizations.project_id = projects.id)) OR projects.visibility_level IN (0,10,20)) AND ("project_features"."issues_access_level" > 0 OR "project_features"."issues_access_level" IS NULL) AND "projects"."archived" = FALSE AND "issues"."due_date" = '2022-01-22' ORDER BY "issues"."created_at" DESC, "issues"."id" DESC LIMIT 20 OFFSET 0

 Limit  (cost=26667.57..26667.57 rows=1 width=1417) (actual time=0.083..0.086 rows=0 loops=1)
   Buffers: shared hit=10
   I/O Timings: read=0.000 write=0.000
   ->  Sort  (cost=26667.57..26667.57 rows=1 width=1417) (actual time=0.082..0.084 rows=0 loops=1)
         Sort Key: issues.created_at DESC, issues.id DESC
         Sort Method: quicksort  Memory: 25kB
         Buffers: shared hit=10
         I/O Timings: read=0.000 write=0.000
         ->  Nested Loop Left Join  (cost=1553.97..26667.56 rows=1 width=1417) (actual time=0.026..0.028 rows=0 loops=1)
               Filter: ((project_features.issues_access_level > 0) OR (project_features.issues_access_level IS NULL))
               Rows Removed by Filter: 0
               Buffers: shared hit=4
               I/O Timings: read=0.000 write=0.000
               ->  Nested Loop  (cost=1553.54..26667.06 rows=1 width=1421) (actual time=0.025..0.027 rows=0 loops=1)
                     Buffers: shared hit=4
                     I/O Timings: read=0.000 write=0.000
                     ->  Nested Loop  (cost=1553.11..23099.06 rows=3883 width=4) (actual time=0.025..0.027 rows=0 loops=1)
                           Buffers: shared hit=4
                           I/O Timings: read=0.000 write=0.000
                           ->  HashAggregate  (cost=1552.54..1554.54 rows=200 width=4) (actual time=0.025..0.026 rows=0 loops=1)
                                 Group Key: namespaces.id
                                 Buffers: shared hit=4
                                 I/O Timings: read=0.000 write=0.000
                                 ->  CTE Scan on base_and_descendants namespaces  (cost=1546.01..1550.03 rows=201 width=4) (actual time=0.023..0.024 rows=0 loops=1)
                                       Buffers: shared hit=4
                                       I/O Timings: read=0.000 write=0.000
                                       CTE base_and_descendants
                                         ->  Recursive Union  (cost=0.43..1546.01 rows=201 width=358) (actual time=0.022..0.023 rows=0 loops=1)
                                               Buffers: shared hit=4
                                               I/O Timings: read=0.000 write=0.000
                                               ->  Index Scan using namespaces_pkey on public.namespaces namespaces_1  (cost=0.43..3.46 rows=1 width=358) (actual time=0.019..0.020 rows=0 loops=1)
                                                     Index Cond: (namespaces_1.id = 26)
                                                     Filter: ((namespaces_1.type)::text = 'Group'::text)
                                                     Rows Removed by Filter: 1
                                                     Buffers: shared hit=4
                                                     I/O Timings: read=0.000 write=0.000
                                               ->  Nested Loop  (cost=0.56..153.85 rows=20 width=358) (actual time=0.001..0.002 rows=0 loops=1)
                                                     I/O Timings: read=0.000 write=0.000
                                                     ->  WorkTable Scan on base_and_descendants  (cost=0.00..0.20 rows=10 width=4) (actual time=0.001..0.001 rows=0 loops=1)
                                                           I/O Timings: read=0.000 write=0.000
                                                     ->  Index Scan using index_namespaces_on_parent_id_and_id on public.namespaces namespaces_2  (cost=0.56..15.35 rows=2 width=358) (actual time=0.000..0.000 rows=0 loops=0)
                                                           Index Cond: (namespaces_2.parent_id = base_and_descendants.id)
                                                           Filter: ((namespaces_2.type)::text = 'Group'::text)
                                                           Rows Removed by Filter: 0
                                                           I/O Timings: read=0.000 write=0.000
                           ->  Index Scan using index_projects_on_namespace_id_and_id on public.projects  (cost=0.56..107.53 rows=19 width=8) (actual time=0.000..0.000 rows=0 loops=0)
                                 Index Cond: (projects.namespace_id = namespaces.id)
                                 Filter: ((NOT projects.archived) AND ((alternatives: SubPlan 1 or hashed SubPlan 2) OR (projects.visibility_level = ANY ('{0,10,20}'::integer[]))))
                                 Rows Removed by Filter: 0
                                 I/O Timings: read=0.000 write=0.000
                                 SubPlan 1
                                   ->  Index Only Scan using index_project_authorizations_on_project_id_user_id on public.project_authorizations  (cost=0.57..3.59 rows=1 width=0) (actual time=0.000..0.000 rows=0 loops=0)
                                         Index Cond: ((project_authorizations.project_id = projects.id) AND (project_authorizations.user_id = 1))
                                         Heap Fetches: 0
                                         I/O Timings: read=0.000 write=0.000
                                 SubPlan 2
                                   ->  Index Only Scan using project_authorizations_pkey on public.project_authorizations project_authorizations_1  (cost=0.57..228.48 rows=6448 width=4) (actual time=0.000..0.000 rows=0 loops=0)
                                         Index Cond: (project_authorizations_1.user_id = 1)
                                         Heap Fetches: 0
                                         I/O Timings: read=0.000 write=0.000
                     ->  Index Scan using idx_issues_on_project_id_and_due_date_and_id_and_state_id on public.issues  (cost=0.43..0.91 rows=1 width=1417) (actual time=0.000..0.000 rows=0 loops=0)
                           Index Cond: ((issues.project_id = projects.id) AND (issues.due_date = '2022-01-22'::date))
                           I/O Timings: read=0.000 write=0.000
               ->  Index Scan using index_project_features_on_project_id on public.project_features  (cost=0.44..0.48 rows=1 width=8) (actual time=0.000..0.000 rows=0 loops=0)
                     Index Cond: (project_features.project_id = projects.id)
                     I/O Timings: read=0.000 write=0.000

Time: 4.911 ms
  - planning: 4.489 ms
  - execution: 0.422 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 10 (~80.00 KiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0
Details for searching all issues (unlikely)
SELECT COUNT(*) FROM "issues" INNER JOIN "projects" ON "projects"."id" = "issues"."project_id" LEFT JOIN project_features ON projects.id = project_features.project_id WHERE (EXISTS (SELECT 1 FROM "project_authorizations" WHERE "project_authorizations"."user_id" = 1933526 AND (project_authorizations.project_id = projects.id)) OR projects.visibility_level IN (0,10,20)) AND ("project_features"."issues_access_level" > 0 OR "project_features"."issues_access_level" IS NULL) AND "projects"."archived" = FALSE AND "issues"."due_date" = '2022-01-21' 

 Aggregate  (cost=93778.07..93778.08 rows=1 width=8) (actual time=39734.782..39734.784 rows=1 loops=1)
   Buffers: shared hit=45464 read=46372 dirtied=2164
   I/O Timings: read=39012.844 write=0.000
   ->  Nested Loop Left Join  (cost=1.30..93770.22 rows=3141 width=0) (actual time=863.558..39726.191 rows=4430 loops=1)
         Filter: ((project_features.issues_access_level > 0) OR (project_features.issues_access_level IS NULL))
         Rows Removed by Filter: 1
         Buffers: shared hit=45464 read=46372 dirtied=2164
         I/O Timings: read=39012.844 write=0.000
         ->  Nested Loop  (cost=0.87..92190.18 rows=3196 width=4) (actual time=858.048..35133.903 rows=4431 loops=1)
               Buffers: shared hit=31889 read=42223 dirtied=2089
               I/O Timings: read=34494.127 write=0.000
               ->  Index Only Scan using idx_issues_on_project_id_and_due_date_and_id_and_state_id on public.issues  (cost=0.43..69232.14 rows=3266 width=4) (actual time=842.243..28186.917 rows=4434 loops=1)
                     Index Cond: (issues.due_date = '2022-01-21'::date)
                     Heap Fetches: 5260
                     Buffers: shared hit=4099 read=34364 dirtied=1583
                     I/O Timings: read=27754.661 write=0.000
               ->  Index Scan using projects_pkey on public.projects  (cost=0.44..7.03 rows=1 width=4) (actual time=1.561..1.561 rows=1 loops=4434)
                     Index Cond: (projects.id = issues.project_id)
                     Filter: ((NOT projects.archived) AND ((alternatives: SubPlan 1 or hashed SubPlan 2) OR (projects.visibility_level = ANY ('{0,10,20}'::integer[]))))
                     Rows Removed by Filter: 0
                     Buffers: shared hit=27655 read=7859 dirtied=371
                     I/O Timings: read=6739.466 write=0.000
                     SubPlan 1
                       ->  Index Only Scan using index_project_authorizations_on_project_id_user_id on public.project_authorizations  (cost=0.57..3.59 rows=1 width=0) (actual time=0.887..0.887 rows=0 loops=4431)
                             Index Cond: ((project_authorizations.project_id = projects.id) AND (project_authorizations.user_id = 1933526))
                             Heap Fetches: 1
                             Buffers: shared hit=14284 read=3446
                             I/O Timings: read=3872.822 write=0.000
                     SubPlan 2
                       ->  Index Only Scan using project_authorizations_pkey on public.project_authorizations project_authorizations_1  (cost=0.57..216.79 rows=6406 width=4) (actual time=0.000..0.000 rows=0 loops=0)
                             Index Cond: (project_authorizations_1.user_id = 1933526)
                             Heap Fetches: 0
                             I/O Timings: read=0.000 write=0.000
         ->  Index Scan using index_project_features_on_project_id on public.project_features  (cost=0.44..0.48 rows=1 width=8) (actual time=1.033..1.033 rows=1 loops=4431)
               Index Cond: (project_features.project_id = projects.id)
               Buffers: shared hit=13575 read=4149 dirtied=75
               I/O Timings: read=4518.717 write=0.000

cold:
Time: 39.745 s
  - planning: 10.393 ms
  - execution: 39.735 s
    - I/O read: 39.013 s
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 45464 (~355.20 MiB) from the buffer pool
  - reads: 46372 (~362.30 MiB) from the OS file cache, including disk I/O
  - dirtied: 2164 (~16.90 MiB)
  - writes: 0

warm:
Time: 201.422 ms
  - planning: 1.956 ms
  - execution: 199.466 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 89947 (~702.70 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

SELECT "issues".* FROM "issues" INNER JOIN "projects" ON "projects"."id" = "issues"."project_id" LEFT JOIN project_features ON projects.id = project_features.project_id WHERE (EXISTS (SELECT 1 FROM "project_authorizations" WHERE "project_authorizations"."user_id" = 1933526 AND (project_authorizations.project_id = projects.id)) OR projects.visibility_level IN (0,10,20)) AND ("project_features"."issues_access_level" > 0 OR "project_features"."issues_access_level" IS NULL) AND "projects"."archived" = FALSE AND "issues"."due_date" = '2022-01-21' ORDER BY "issues"."created_at" DESC, "issues"."id" DESC LIMIT 20 OFFSET 0

 Limit  (cost=98125.19..98125.24 rows=20 width=1418) (actual time=2475.253..2475.263 rows=20 loops=1)
   Buffers: shared hit=86493 read=1956
   I/O Timings: read=2208.665 write=0.000
   ->  Sort  (cost=98125.19..98133.04 rows=3141 width=1418) (actual time=2475.251..2475.257 rows=20 loops=1)
         Sort Key: issues.created_at DESC, issues.id DESC
         Sort Method: top-N heapsort  Memory: 77kB
         Buffers: shared hit=86493 read=1956
         I/O Timings: read=2208.665 write=0.000
         ->  Nested Loop Left Join  (cost=1.30..98041.61 rows=3141 width=1418) (actual time=2.882..2466.080 rows=4430 loops=1)
               Filter: ((project_features.issues_access_level > 0) OR (project_features.issues_access_level IS NULL))
               Rows Removed by Filter: 1
               Buffers: shared hit=86487 read=1956
               I/O Timings: read=2208.665 write=0.000
               ->  Nested Loop  (cost=0.87..96461.58 rows=3196 width=1422) (actual time=2.869..2437.817 rows=4431 loops=1)
                     Buffers: shared hit=68763 read=1956
                     I/O Timings: read=2208.665 write=0.000
                     ->  Index Scan using idx_issues_on_project_id_and_due_date_and_id_and_state_id on public.issues  (cost=0.43..73503.53 rows=3266 width=1418) (actual time=2.792..2366.900 rows=4434 loops=1)
                           Index Cond: (issues.due_date = '2022-01-21'::date)
                           Buffers: shared hit=33297 read=1956
                           I/O Timings: read=2208.665 write=0.000
                     ->  Index Scan using projects_pkey on public.projects  (cost=0.44..7.03 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=4434)
                           Index Cond: (projects.id = issues.project_id)
                           Filter: ((NOT projects.archived) AND ((alternatives: SubPlan 1 or hashed SubPlan 2) OR (projects.visibility_level = ANY ('{0,10,20}'::integer[]))))
                           Rows Removed by Filter: 0
                           Buffers: shared hit=35466
                           I/O Timings: read=0.000 write=0.000
                           SubPlan 1
                             ->  Index Only Scan using index_project_authorizations_on_project_id_user_id on public.project_authorizations  (cost=0.57..3.59 rows=1 width=0) (actual time=0.006..0.006 rows=0 loops=4431)
                                   Index Cond: ((project_authorizations.project_id = projects.id) AND (project_authorizations.user_id = 1933526))
                                   Heap Fetches: 1
                                   Buffers: shared hit=17730
                                   I/O Timings: read=0.000 write=0.000
                           SubPlan 2
                             ->  Index Only Scan using project_authorizations_pkey on public.project_authorizations project_authorizations_1  (cost=0.57..216.79 rows=6406 width=4) (actual time=0.000..0.000 rows=0 loops=0)
                                   Index Cond: (project_authorizations_1.user_id = 1933526)
                                   Heap Fetches: 0
                                   I/O Timings: read=0.000 write=0.000
               ->  Index Scan using index_project_features_on_project_id on public.project_features  (cost=0.44..0.48 rows=1 width=8) (actual time=0.005..0.005 rows=1 loops=4431)
                     Index Cond: (project_features.project_id = projects.id)
                     Buffers: shared hit=17724
                     I/O Timings: read=0.000 write=0.000

cold:
Time: 2.480 s
  - planning: 4.175 ms
  - execution: 2.475 s
    - I/O read: 2.209 s
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 86493 (~675.70 MiB) from the buffer pool
  - reads: 1956 (~15.30 MiB) from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

warm:
Time: 192.688 ms
  - planning: 1.646 ms
  - execution: 191.042 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 88449 (~691.00 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

How to set up and validate locally

Assign some due dates to some issues e.g.
"TODAY"- http://gdk.test:3000/flightjs/Flight/-/issues/36
"TOMORROW"- http://gdk.test:3000/flightjs/Flight/-/issues/35

Hit the API to see if the right issues are returned:
`#35` and `#36`- http://gdk.test:3000/api/v4/projects/6/issues?due_date=any
`#36`- http://gdk.test:3000/api/v4/projects/6/issues?due_date=today
`#35`- http://gdk.test:3000/api/v4/projects/6/issues?due_date=tomorrow

`#35` and `#36`- http://gdk.test:3000/api/v4/groups/26/issues?due_date=any
`#36`- http://gdk.test:3000/api/v4/groups/26/issues?due_date=today
`#35`- http://gdk.test:3000/api/v4/groups/26/issues?due_date=tomorrow

`#35` and `#36`- http://gdk.test:3000/api/v4/issues?due_date=any&scope=all
`#36`- http://gdk.test:3000/api/v4/issues?due_date=today&scope=all
`#35`- http://gdk.test:3000/api/v4/issues?due_date=tomorrow&scope=all

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Lee Tickett

Merge request reports