How can I drop an index on all partitions?
-
01-10-2020 - |
Question
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
Solution
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.
OTHER TIPS
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:
- Create the new partition
- Check if the new partition has indexes on it
- Check what the name of the parent table index is that matches the column list of each index
- 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.