Skip to content

Add search parameter to the environments controller

What does this MR do and why?

Extracted from PoC for environments search (!86115 - closed)

And based on the Fix performance of the environments search (!96774 - merged)

This MR adds the search parameter to the environments controller which will be used #10754 (closed)

Migration logs

Click to expand
➜  gitlab git:(10754-search-for-environment-name-in-the-environments-overview-page) ✗ ./bin/rails db:rollback:main STEP=2
main: == 20220909114220 DropEnvironmentsProjectNameLowerPatternOpsIndex: reverting ==
main: -- transaction_open?()
main:    -> 0.0000s
main: -- index_exists?(:environments, "project_id, lower(name) varchar_pattern_ops", {:name=>"index_environments_on_project_name_varchar_pattern_ops", :algorithm=>:concurrently})
main:    -> 0.0467s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0002s
main: -- add_index(:environments, "project_id, lower(name) varchar_pattern_ops", {:name=>"index_environments_on_project_name_varchar_pattern_ops", :algorithm=>:concurrently})
main:    -> 0.0049s
main: -- execute("RESET statement_timeout")
main:    -> 0.0002s
main: == 20220909114220 DropEnvironmentsProjectNameLowerPatternOpsIndex: reverted (0.0621s) 

main: == 20220909113809 AddEnvironmentsProjectNameLowerPatternOpsStateIndex: reverting 
main: -- transaction_open?()
main:    -> 0.0000s
main: -- indexes(:environments)
main:    -> 0.0048s
main: -- remove_index(:environments, {:algorithm=>:concurrently, :name=>"index_environments_on_project_name_varchar_pattern_ops_state"})
main:    -> 0.0029s
main: == 20220909113809 AddEnvironmentsProjectNameLowerPatternOpsStateIndex: reverted (0.0092s) 

➜  gitlab git:(10754-search-for-environment-name-in-the-environments-overview-page) ✗ ./bin/rails db:migrate:main        
main: == 20220909113809 AddEnvironmentsProjectNameLowerPatternOpsStateIndex: migrating 
main: -- transaction_open?()
main:    -> 0.0000s
main: -- index_exists?(:environments, "project_id, lower(name) varchar_pattern_ops, state", {:name=>"index_environments_on_project_name_varchar_pattern_ops_state", :algorithm=>:concurrently})
main:    -> 0.0106s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0002s
main: -- add_index(:environments, "project_id, lower(name) varchar_pattern_ops, state", {:name=>"index_environments_on_project_name_varchar_pattern_ops_state", :algorithm=>:concurrently})
main:    -> 0.0032s
main: -- execute("RESET statement_timeout")
main:    -> 0.0002s
main: == 20220909113809 AddEnvironmentsProjectNameLowerPatternOpsStateIndex: migrated (0.0199s) 

main: == 20220909114220 DropEnvironmentsProjectNameLowerPatternOpsIndex: migrating ==
main: -- transaction_open?()
main:    -> 0.0000s
main: -- indexes(:environments)
main:    -> 0.0045s
main: -- remove_index(:environments, {:algorithm=>:concurrently, :name=>"index_environments_on_project_name_varchar_pattern_ops"})
main:    -> 0.0028s
main: == 20220909114220 DropEnvironmentsProjectNameLowerPatternOpsIndex: migrated (0.0087s) 

SQL queries and plans:

Summary table

query name old MiB accessed narrow search MiB accessed generic search MiB accessed
getting available/closed counters 22.10 MiB 1.30 MiB 33 MiB
Selecting number of environments per folder 27.60 MiB 1.20 MiB 27.20 MiB
Actually getting top 20 environments for each folder 27.70 MiB 1.20 MiB 27.20 MiB

(last 2 rows are not duplicates, they just process very similar rows)

getting available/closed counters

Specific queries like ‘review/my\_review%’ are very fast
explain SELECT COUNT(*) AS count_all, "environments"."state" AS environments_state FROM "environments" WHERE "environments"."project_id" = 278964 AND (LOWER(environments.name) LIKE LOWER('review/r') || '%') GROUP BY "environments"."state"

Time: 1.422 ms
  - planning: 0.340 ms
  - execution: 1.082 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

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

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42639

Less specific ones are slower, e.g. search for `r%`
explain SELECT COUNT(*) AS count_all, environments.state AS environments_state FROM environments WHERE environments.project_id = 278964 AND (LOWER(environments.name) LIKE LOWER(r) || %) GROUP BY environments.state

Time: 109.947 ms
  - planning: 0.250 ms
  - execution: 109.697 ms
    - I/O read: 91.657 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 554 (~4.30 MiB) from the buffer pool
  - reads: 3676 (~28.70 MiB) from the OS file cache, including disk I/O
  - dirtied: 422 (~3.30 MiB)
  - writes: 0

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42640

But they weren't too fast before too:
explain SELECT COUNT(*) AS count_all, environments.state AS environments_state FROM environments WHERE environments.project_id = 278964 GROUP BY environments.state

Time: 217.208 ms
  - planning: 0.187 ms
  - execution: 217.021 ms
    - I/O read: 206.575 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 2608 (~20.40 MiB) from the buffer pool
  - reads: 218 (~1.70 MiB) from the OS file cache, including disk I/O
  - dirtied: 56 (~448.00 KiB)
  - writes: 0

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42641

Selecting number of environments per folder

Again, specific search is very fast
explain SELECT COUNT(*) AS count_all, COALESCE(environment_type, id::text) AS coalesce_environment_type_id_text, COALESCE(environment_type, name) AS coalesce_environment_type_name FROM environments WHERE environments.project_id = 278964 AND (LOWER(environments.name) LIKE LOWER(review/r) || %) AND (environments.state IN (available)) GROUP BY COALESCE(environment_type, id::text), COALESCE(environment_type, name) LIMIT 10001

Time: 1.453 ms
  - planning: 0.671 ms
  - execution: 0.782 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

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

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42642

But more generic is slower
explain SELECT COUNT(*) AS count_all, COALESCE(environment_type, id::text) AS coalesce_environment_type_id_text, COALESCE(environment_type, name) AS coalesce_environment_type_name FROM environments WHERE environments.project_id = 278964 AND (LOWER(environments.name) LIKE LOWER(r) || %) AND (environments.state IN (available)) GROUP BY COALESCE(environment_type, id::text), COALESCE(environment_type, name) LIMIT 10001

Time: 18.722 ms
  - planning: 0.296 ms
  - execution: 18.426 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

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

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42643

And again it wasn't super fast before
explain SELECT COUNT(*) AS count_all, COALESCE(environment_type, id::text) AS coalesce_environment_type_id_text, COALESCE(environment_type, name) AS coalesce_environment_type_name FROM environments WHERE environments.project_id = 278964 AND (environments.state IN (available)) GROUP BY COALESCE(environment_type, id::text), COALESCE(environment_type, name) LIMIT 10001

Time: 40.447 ms
  - planning: 0.307 ms
  - execution: 40.140 ms
    - I/O read: 29.287 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 3531 (~27.60 MiB) from the buffer pool
  - reads: 8 (~64.00 KiB) from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42644

Actually getting top 20 environments for each folder

Again, fast specific search
explain SELECT COALESCE(environment_type, id::text), COALESCE(environment_type, name) AS folder, COUNT(*) AS size, MAX(id) AS last_id FROM environments WHERE environments.project_id = 278964 AND (LOWER(environments.name) LIKE LOWER(review/r) || %) AND (environments.state IN (available)) GROUP BY COALESCE(environment_type, id::text), COALESCE(environment_type, name) ORDER BY folder ASC LIMIT 20 OFFSET 0

Time: 1.624 ms
  - planning: 0.581 ms
  - execution: 1.043 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

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

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42645

slow generic search
explain SELECT COALESCE(environment_type, id::text), COALESCE(environment_type, name) AS folder, COUNT(*) AS size, MAX(id) AS last_id FROM “environments” WHERE “environments”.“project_id” = 278964 AND (LOWER(environments.name) LIKE LOWER(‘r’) || ‘%’) AND (“environments”.“state” IN (‘available’)) GROUP BY COALESCE(environment_type, id::text), COALESCE(environment_type, name) ORDER BY folder ASC LIMIT 20 OFFSET 0

Time: 20.991 ms
  - planning: 0.324 ms
  - execution: 20.667 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

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

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42646

And slow without search
explain SELECT COALESCE(environment_type, id::text), COALESCE(environment_type, name) AS folder, COUNT(*) AS size, MAX(id) AS last_id FROM environments WHERE environments.project_id = 278964  AND (environments.state IN (available)) GROUP BY COALESCE(environment_type, id::text), COALESCE(environment_type, name) ORDER BY folder ASC LIMIT 20 OFFSET 0

Time: 19.457 ms
  - planning: 3.020 ms
  - execution: 16.437 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

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

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/12016/commands/42647

Screenshots or screen recordings

No UI changes yet.

How to set up and validate locally

  1. Enable the FF
    Feature.enable(:environments_search)
  2. Go to the environments page, create a few environments(use folders like review/my-review...)
  3. open developer console and find requests like:
  1. add &search=something to them -->

MR acceptance checklist

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

Related to #10754 (closed)

Edited by Vladimir Shushlin

Merge request reports