Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patrickjennings/64d1b71e2c16f5fddf18c2bef00bc529 to your computer and use it in GitHub Desktop.
Save patrickjennings/64d1b71e2c16f5fddf18c2bef00bc529 to your computer and use it in GitHub Desktop.

Example of current searchClientsByAttributes in main, for a particular client attribute value, providing increasing offset values.

explain analyze select ce1_0.ID
   from CLIENT ce1_0
   join CLIENT_ATTRIBUTES a1_0
     on ce1_0.ID=a1_0.CLIENT_ID
  where ce1_0.REALM_ID='redacted'
    and a1_0.NAME='redacted'
    and substr(a1_0.VALUE,1,255)=substr('true',1,255)
    and a1_0.VALUE='true'
  order by ce1_0.CLIENT_ID
 offset 1 rows fetch first 2 rows only;
                                                                                QUERY PLAN                                                                                   
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit  (cost=293.89..879.47 rows=2 width=73) (actual time=0.082..0.095 rows=2 loops=1)
  ->  Nested Loop  (cost=1.10..4051928.03 rows=13839 width=73) (actual time=0.033..0.094 rows=3 loops=1)
        ->  Index Scan using idx_315318_uk_b71cjlbenv945rb6gcon438at on client ce1_0  (cost=0.55..678915.15 rows=500133 width=73) (actual time=0.020..0.062 rows=3 loops=1)
              Index Cond: ((realm_id)::text = 'redacted'::text)
        ->  Index Scan using idx_315336_primary on client_attributes a1_0  (cost=0.56..6.74 rows=1 width=37) (actual time=0.009..0.009 rows=1 loops=3)
              Index Cond: (((client_id)::text = (ce1_0.id)::text) AND ((name)::text = 'redacted'::text))
              Filter: ((value = 'true'::text) AND (substr(value, 1, 255) = 'true'::text))
Planning Time: 0.614 ms
Execution Time: 0.121 ms
(9 rows)

A small offset specified causes the query plan to utilize the indices effectively.

explain analyze select ce1_0.ID
   from CLIENT ce1_0
   join CLIENT_ATTRIBUTES a1_0
     on ce1_0.ID=a1_0.CLIENT_ID
  where ce1_0.REALM_ID='redacted'
    and a1_0.NAME='redacted'
    and substr(a1_0.VALUE,1,255)=substr('true',1,255)
    and a1_0.VALUE='true'
  order by ce1_0.CLIENT_ID
 offset 1000 rows fetch first 2 rows only;
                                                                                         QUERY PLAN                                                                                        
  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--
Limit  (cost=151519.25..151820.28 rows=2 width=73) (actual time=12.742..14.879 rows=2 loops=1)
  ->  Gather Merge  (cost=1001.13..2084021.39 rows=13839 width=73) (actual time=5.059..14.832 rows=1002 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        ->  Nested Loop  (cost=1.10..2081424.00 rows=5766 width=73) (actual time=0.045..6.141 rows=335 loops=3)
              ->  Parallel Index Scan using idx_315318_uk_b71cjlbenv945rb6gcon438at on client ce1_0  (cost=0.55..675997.70 rows=208389 width=73) (actual time=0.022..2.737 rows=338 loops=3
)
                    Index Cond: ((realm_id)::text = 'redacted'::text)
              ->  Index Scan using idx_315336_primary on client_attributes a1_0  (cost=0.56..6.74 rows=1 width=37) (actual time=0.009..0.009 rows=1 loops=1014)
                    Index Cond: (((client_id)::text = (ce1_0.id)::text) AND ((name)::text = 'redacted'::text))
                    Filter: ((value = 'true'::text) AND (substr(value, 1, 255) = 'true'::text))
Planning Time: 0.288 ms
Execution Time: 14.918 ms
(12 rows)

As greater offsets are provided, the DB must do scans over the index results, requiring additional execution time.

explain analyze select ce1_0.ID
   from CLIENT ce1_0
   join CLIENT_ATTRIBUTES a1_0
     on ce1_0.ID=a1_0.CLIENT_ID
  where ce1_0.REALM_ID='redacted'
    and a1_0.NAME='redacted'
    and substr(a1_0.VALUE,1,255)=substr('true',1,255)
    and a1_0.VALUE='true'
  order by ce1_0.CLIENT_ID
 offset 10000 rows fetch first 2 rows only;
                                                                                 QUERY PLAN                                                                                   
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit  (cost=256025.24..256025.47 rows=2 width=73) (actual time=2315.872..2328.133 rows=2 loops=1)
  ->  Gather Merge  (cost=254858.49..256203.98 rows=11532 width=73) (actual time=2309.449..2327.715 rows=10002 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        ->  Sort  (cost=253858.47..253872.88 rows=5766 width=73) (actual time=2305.774..2306.225 rows=3657 loops=3)
              Sort Key: ce1_0.client_id
              Sort Method: top-N heapsort  Memory: 3114kB
              Worker 0:  Sort Method: top-N heapsort  Memory: 3128kB
              Worker 1:  Sort Method: top-N heapsort  Memory: 3123kB
              ->  Nested Loop  (cost=1215.15..253498.28 rows=5766 width=73) (actual time=143.732..2104.580 rows=161385 loops=3)
                    ->  Parallel Bitmap Heap Scan on client_attributes a1_0  (cost=1214.60..207602.91 rows=5768 width=37) (actual time=143.700..560.355 rows=161385 loops=3)
                          Recheck Cond: (((name)::text = 'redacted'::text) AND (substr(value, 1, 255) = 'true'::text))
                          Filter: (value = 'true'::text)
                          Heap Blocks: exact=98083
                          ->  Bitmap Index Scan on idx_client_att_by_name_value  (cost=0.00..1211.14 rows=83071 width=0) (actual time=67.206..67.206 rows=502674 loops=1)
                                Index Cond: (((name)::text = 'redacted'::text) AND (substr(value, 1, 255) = 'true'::text))
                    ->  Index Scan using idx_315318_primary on client ce1_0  (cost=0.55..7.96 rows=1 width=73) (actual time=0.009..0.009 rows=1 loops=484154)
                          Index Cond: ((id)::text = (a1_0.client_id)::text)
                          Filter: ((realm_id)::text = 'redacted'::text)
Planning Time: 0.296 ms
Execution Time: 2328.706 ms
(21 rows)

At large offset values, the query plan changes to heap scan, greatly negatively affecting the query cost and execution time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment