0

I have quite a few index tables in my DB. I want to delete them and only index those tables that are very big. How Can i delete them?

I can do

select relname from pg_class where relkind='i'; and drop index

But I think this query will also delete some system tables. How do i do this without affecting thr functioning of the DB?

5
  • 2
    drop table drops a table not an index. Your query returns indexes. It is unclear to me, what exactly you want to drop: any table that has an index or just all indexes? Commented Feb 19, 2018 at 6:52
  • "only index those tables that are small" This is fundamentally backwards. You want to index big tables so that queries on them are faster. Small tables (a couple thousand rows or less) don't benefit from having them very much; PostgreSQL will even ignore them completely if it estimates the cost of the extra disk reads negate the faster search advantage. What are you actually trying to accomplish by deleting indexes? Commented Feb 19, 2018 at 7:31
  • @a_horse_with_no_name sorry. i changed it to drop index. i want to drop indexes not tables. Commented Feb 19, 2018 at 9:16
  • @jpmc26 sorry, i would want to index only the very big tables. made changes. I want to delete indexes so that the DB size reduces dramatically and backup of the DB becomes faster. I want to install DB on another server. Commented Feb 19, 2018 at 9:18
  • @user2238284 PostgreSQL does not include the on-disk contents of the index in dump files: dba.stackexchange.com/a/123788/23369. Dropping indexes won't speed up the dump. Dropping the big indexes might speed up the restore, but you probably want to recreate the indexes on the other machine anyway. You could also just exclude the indexes from the restore instead of dropping them on the source DB. Commented Feb 19, 2018 at 10:40

2 Answers 2

5

If you are using pg_class to find all indexes, you need to join that to pg_namespace and filter on the schema where your tables (and indexes) are stored.

It is much easier to pg_indexes instead though:

select schemaname, 
       indexname, 
       tablename, 
       format('drop index %I.%I;', schemaname, indexname) as drop_statement
from pg_indexes
where schemaname not in ('pg_catalog', 'pg_toast');

That will however also show you indexes that are used for primary keys.

If you want to exclude primary key indexes, you can use something like this:

select s.nspname as schemaname,
       i.relname as indexname,
       t.relname as tablename,
       format('drop index %I.%I;', s.nspname, i.relname) as drop_statement
from pg_index idx
  join pg_class i on i.oid = idx.indexrelid
  join pg_class t on t.oid = idx.indrelid
  join pg_namespace s on i.relnamespace = s.oid
where s.nspname  not in ('pg_catalog', 'pg_toast')
  and not idx.indisprimary;

If you also want to exclude unique indexes, just add and not idx.indisunique to the where condition.

Sign up to request clarification or add additional context in comments.

Comments

0

Here a sample that actually drops the indices. Based on @a_horse_with_no_name answer.

DO $$
DECLARE 
    ind record;
BEGIN
    FOR ind IN 
        SELECT 
            s.nspname as schemaname,
            i.relname as indexname,
            t.relname as tablename,
            format('drop index %I.%I;', s.nspname, i.relname) as drop_statement
        FROM pg_index idx
            join pg_class i on i.oid = idx.indexrelid
            join pg_class t on t.oid = idx.indrelid
            join pg_namespace s on i.relnamespace = s.oid
        WHERE s.nspname  not in ('pg_catalog', 'pg_toast')
            AND NOT idx.indisprimary
        LOOP
            RAISE NOTICE 'Command: %', ind.drop_statement;
            EXECUTE ind.drop_statement;
    END LOOP;   
    
    COMMIT;
END$$;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.