pgexperts / pgx_scripts

A collection of useful little scripts for database analysis and administration, created by our team at PostgreSQL Experts.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

btree_index_atts CTE should assign attnum's starting at 1

fmcgeough opened this issue · comments

I think : regexp_split_to_table(indkey::text, ' ')::smallint AS attnum,

should be : generate_series(1, array_length(indkey,1))::smallint AS attnum,

the join with pg_attributes include attnum but pg_attributes will number the attributes for the index at 1. the pg_index indkey is the physical index to the column within the table.

thanks for this query. its very helpful.

Thanks for the report! Let me summarize my understanding.

To my reading, both pg_index.indkey and pg_attribute use 1-based numbering for columns[1]. However, 0 has different meanings between those two tables:

  • pg_index.indkey = 0 means the index is "an expression over table columns" (like 'WHERE my_column IS NOT NULL')
  • pg_attribute.attnum = 0 means… actually, I'm not sure. The docs just say "System columns, such as oid, have (arbitrary) negative numbers" without mentioning 0.

If pg_attribute.attnum never has zeroes in it, then the JOIN won't return any multicolumn indexes:

    JOIN btree_index_atts AS ind_atts ON pg_attribute.attrelid = ind_atts.indexrelid AND pg_attribute.attnum = ind_atts.attnum

… but that's also true with your proposed solution, right?

If, on the other hand, pg_attribute.attnum can have zeroes in it, then we might get misleading results. Was that your concern?

Sorry if I'm missing the point; if so, please correct me. Of course, either way, the larger issue is that expression indexes won't (currently) be included in the bloat report.

Thanks,
Quinn

[1] From the docs:

commented

The problem is that regexp_split_to_table(indkey::text, ' ')::smallint AS attnum returns the relative column numbers of the columns in the table. For example column number 10 and 11 if your index is created on these columns

The column pg_attribute.attnum contains the relative columns in the index, which always starts at 1. When you join the on columns from regexp_split_to_table(indkey::text, ' ') with pg_attribute.attnum you and up with a lot of missing lines. In the case where the index is on column 10 and 11 of the table, you remove the index completely from the resultset because the is no 10th and 11th column in the index.

Solution

  • Remove line 11 regexp_split_to_table(indkey::text, ' ')::smallint AS attnum,
  • Change the join condition on line 35 to JOIN btree_index_atts AS ind_atts ON pg_attribute.attrelid = ind_atts.indexrelid ie remove the join condition pg_attribute.attnum = ind_atts.attnum. This way you join all the columns in the index.