Introduction – Invisible or Hidden Index.
Any database conversion offers valuable insights into how things work across platforms or how to achieve similar functionality in the target database. Invisible indexes are one such feature that is often requested in PostgreSQL when migrating away, due to their use case of create new or marking existing indexes as invisible for the optimizer.
Making indexes invisible can be beneficial for several use cases, such as:
- Creating invisible indexes allows for simulating and measuring impacts before actually dropping duplicate or unused indexes.
- Temporarily marking an index as invisible can influence the execution plan to avoid using it as an index access path option.
Oracle – Invisible Index
Before delving into the options available to achieve similar features in PostgreSQL, let’s first understand how it would work in Oracle with a sample table.
Sample Oracle examples
create table test_invisible as
select level as col1, level as col2,
rpad('a',level,'x') as col3
from dual
connect by rownum < 501;
create index test_invisible_idx1 on
test_invisible(col1);
create index test_invisible_idx2 on
test_invisible(col1,col2);
explain plan for
select /*+ NO_PARALLEL */ * from test_invisible
where col1 = 1;
select * from table(dbms_xplan.display);

In our scenario, let’s assume we want to eliminate a single column index (test_invisible_idx1). We’ll alter the index to be invisible and then verify the execution plan to assess the impact on performance.
alter index test_invisible_idx1 invisible;
explain plan for
select /*+ NO_PARALLEL */ * from test_invisible where col1 = 1;
select * from table(dbms_xplan.display);

In Oracle, making any index invisible has a global effect—it’s not limited to the current session or specific users.
PostgreSQL – Invisible Index(hypopg Extension)
Making indexes invisible isn’t officially supported as part of the ALTER INDEX command in vanilla PostgreSQL. However, leveraging the Extensions ecosystem allows us to achieve somewhat similar functionality in PostgreSQL.
HypoPG extensions enable us to create or mark existing indexes as invisible for the current session scope, and it’s applied only within the Explain Plan.. From Release 1.4.0 We have the option to mark existing indexes as hidden, and we can validate the changes in the execution plan post marking it as hidden using EXPLAIN.
create table test_invisible as select col1, col1::text as col2,
rpad('a',col1,'x') as col3
from generate_series(1,500) as col1;
create index test_invisible_idx1 on
test_invisible(col1);
create index test_invisible_idx2 on
test_invisible(col1,col2);
create extension hypopg;
select hypopg_hide_index('test_invisible_idx1'::regclass);
select * from hypopg_hidden_indexes;
explain select * from test_invisible where col1 = 1;

We utilize the hypopg_hide_index function to mark our index test_invisible_idx1 as invisible, and then we verify the changes in the execution plan using EXPLAIN.Marking indexes with hypopg is not a global change; it impacts only the current session and application, affecting the Explain plan exclusively.
When connected to a new session or connection, hidden indexes marked with hypopg are not visible.

In PostgreSQL, for invisible indexes functionality on existing indexes, we can rely on the hypoPG extension. Although its effectiveness isn’t global across sessions and in actual SQL execution, it does provide a way for users to test queries with the Explain plan, mark indexes as hidden, and observe the effect on the access path.