6

If I create an index on a partitioned table, each partition gets its own index. These are not dropped if I drop the main index.

Is there an easy way to do this?

I have written a function that looks for all the indexes that match the top level index name with a partition suffix, and that works fine for indexes that were created on partitions.

However, when Greenplum adds a new partition through a default partition split, it generates a new index for that partition with a totally different naming convention.

Existing partitions get a name like indexname_1_prt_partitionname

New partitions get a name like tablename_1_prt_partitionname_indexcolumn

Any idea how I can identify that the new partition index is part of the parent index, when the name doesn't match? Or do I just call my index deleter twice with two different patterns to match?

I will be using either Bell's query below, or this one which is adapted to take a partition index (in case we have already deleted the head index):

SELECT child_index.indexrelid::regclass
  FROM pg_index AS partition_index
    -- Find the partition that the partition index is on
    INNER JOIN pg_partition_rule parindex_rule ON parindex_rule.parchildrelid = partition_index.indrelid
    -- Follup up to the partitioning scheme
    INNER JOIN pg_partition ON pg_partition.oid = parindex_rule.paroid
    -- Follow the links through to the individual partitions
    INNER JOIN pg_partition_rule ON pg_partition_rule.paroid = pg_partition.oid
    -- Find the indexes on each partition
    INNER JOIN pg_index AS child_index ON child_index.indrelid = pg_partition_rule.parchildrelid
      -- Which are on the same field as the named index
      AND child_index.indkey = partition_index.indkey
      -- Using the same comparison operator
      AND child_index.indclass = partition_index.indclass
  -- Filtered for the index we're trying to drop
  WHERE partition_index.indexrelid = 'schema.partitionindexname'::regclass
5

Greenplum doesn't (as at version 4.3.8) maintain a record in the catalogue linking indexes on partitions to indexes on base tables. The best option is to follow the partitions and find indexes on the partitions matching the definition of the base index.

CREATE OR REPLACE FUNCTION drop_child_indexes (index_name varchar)
RETURNS VOID
AS
$functionBody$
DECLARE
  child_index_name varchar;
BEGIN

  FOR child_index_name IN
    SELECT child_index.indexrelid::regclass
      FROM pg_index AS parent_index
        -- Find the partitioning scheme for the table the index is on
        INNER JOIN pg_partition ON pg_partition.parrelid = parent_index.indrelid
        -- Follow the links through to the individual partitions
        INNER JOIN pg_partition_rule ON pg_partition_rule.paroid = pg_partition.oid
        -- Find the indexes on each partition
        INNER JOIN pg_index AS child_index ON child_index.indrelid = pg_partition_rule.parchildrelid
          -- Which are on the same field as the named index
          AND child_index.indkey = parent_index.indkey
          -- Using the same comparison operator
          AND child_index.indclass = parent_index.indclass
      -- Filtered for the index we're trying to drop
      WHERE parent_index.indexrelid = $1::regclass::oid
      -- Drop leaves first, even if it doesn't really matter in this case
      ORDER BY pg_partition.parlevel DESC

LOOP
  RAISE NOTICE '%', child_index_name||' ';
  EXECUTE 'DROP INDEX '||child_index_name||';';
END LOOP;

END
$functionBody$
LANGUAGE plpgsql;

If there another index with the same definition (fields, comparison operators) it's partition indexes will also be dropped. Not a perfect answer but better than substring matching.

  • 1
    That's insane. I don't mean your solution - very good - but it's insane that we need to do ridiculous things like this just to drop an index! – PhilHibbs May 3 '16 at 13:11
  • How do I use the indrelid to drop the index? – PhilHibbs May 3 '16 at 13:30
  • I've updated the example to use the query results in a function wrapper – Bell May 3 '16 at 16:34
  • I see. I tried casting the regclass to varchar and it didn't work, so I assumed that you couldn't just assign to a varchar either. Also won't the code above identify other indexes? If I want to drop an index on a,b and there is also an index just on b, I suspect the b index will also be dropped. – PhilHibbs May 4 '16 at 8:05
  • When a value is used PL/pgSQL from a resultset (SELECT INTO varname, FOR varname IN SELECT) or from a parameter it is coerced through a to_string-then-from_string process. So while you'd need a valid cast in a query result you don't need one in this case. If you particularly wanted a cast you could build one based on this implementation detail as well - there's an example at grokbase.com/t/postgresql/pgsql-hackers/042vq8wcb0/… – Bell May 4 '16 at 8:32
0

My new solution to this is to rename the index when creating a new partition. We are already doing our partition creation in a plsql procedure so the process will be this:

  1. Create the new partition
  2. Check if the new partition has indexes on it
  3. Check what the name of the parent table index is that matches the column list of each index
  4. Rename the index to match the corresponding parent table index

This way our indexes will always have consistent names and will never get duplicated. This means we can then use name-matching to drop the child indexes instead of column-list matching. I'll post some code when I've got it working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.