Regarding GIN Index in Postgresql I am facing an issue that Even after creating a GIN INDEX execution plan is taking much time.

select email from customer where lower(email) like '%gmail';
CREATE INDEX idx1  ON customer USING gin  (lower(email) gin_trgm_ops);.

Index created as  "idx1" gin (lower(email::text) gin_trgm_ops)


explain plan gives as below

###
 Bitmap Heap Scan on customer  (cost=168.51..367.36 rows=194 width=22) (actual time=381.844..1807.673 rows=931488 loops=1)
   Recheck Cond: (lower((email)::text) ~~ '%gmail.com'::text)
   Rows Removed by Index Recheck: 556
   Heap Blocks: exact=53254
   -&gt;  Bitmap Index Scan on idx1  (cost=0.00..168.46 rows=194 width=0) (actual time=372.263..372.263 rows=933383 loops=1)
         Index Cond: (lower((email)::text) ~~ '%gmail.com'::text)
 Planning time: 0.741 ms
 Execution time: 1988.646 ms
(8 rows)


Please let me know if this can be fine-tuned further
You are returning 1 million rows.  Returning 1 million rows is going to take some time.  Especially when it has to do a pattern matching recheck of each row.  How fast do you expect this to be?

Your best bet is fixing things on the application side.  Why do you need a million rows?  What are doing with them?  And if you do need to return that many, why do you need to do it so often that it matters if it takes an extra second to do?  But beyond that:


Get a faster computer.
Upgrade to a recent version of PostgreSQL and see if you can get parallel execution (that would depend on what percentage of your table is being returned by this query)
Get rid of the "lower" function and use "ilike" rather than "like".  Indexes based on gin_trgm_ops support "ilike" queries naturally with no special steps needed.
Use an ordinary btree index on reverse(lower(email)) so that the wild card is at the end rather than the beginning of the query string.  Better yet, store the email in that form to start with, so expression indexes are not needed.