From: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> |
---|---|
To: | plu tard <plutard12(at)hotmail(dot)com> |
Cc: | pgsql-general(at)postgresql(dot)org |
Subject: | Re: Finding foreign keys that are missing indexes |
Date: | 2008-12-28 21:31:23 |
Message-ID: | 11236.1230499883@sss.pgh.pa.us |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general |
plu tard <plutard12(at)hotmail(dot)com> writes:
> I'm aware that if you create a foreign key constraint, no indexes are automatically created.
> I would like to find a way to programatically inspect all my foreign keys and identify possibly missing indexes on either table (either the table defining the constraint or the table being referenced).
You don't have to worry about the referenced table because it must have
a unique index matching the referenced columns. On the referencing
side, the thing to do is try to match up pg_constraint.conkey with
pg_index.indkey. Something like
db=# create table m (f1 int, f2 int, primary key(f1));
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "m_pkey" for table "m"
CREATE TABLE
db=# create table s (r1 int, r2 int, foreign key (r1) references m);
CREATE TABLE
db=# select conrelid::regclass,conname from pg_constraint where contype = 'f'
and not exists (select 1 from pg_index where indrelid=conrelid and conkey[1] = indkey[0]);
conrelid | conname
----------+-----------
s | s_r1_fkey
(1 row)
db=# create index si on s(r1);
CREATE INDEX
db=# select conrelid::regclass,conname from pg_constraint where contype = 'f'
and not exists (select 1 from pg_index where indrelid=conrelid and conkey[1] = indkey[0]);
conrelid | conname
----------+---------
(0 rows)
The above only works for single-column fkeys and indexes, though, and
extending it to multicolumn is a bit of a PITA. You can't just compare
conkey as a whole to indkey because (for historical reasons) indkey has
zero-based array indexes instead of 1-based. Even aside from that, we'd
really want the code to recognize that an index on (f1,f2) is usable for
a constraint on (f2,f1). So it seems that you need something like this:
db=# create function sortarray(int2[]) returns int2[] as
db-# 'select array(select $1[i] from generate_series(array_lower($1,1),array_upper($1,1)) i order by 1)' language sql;
CREATE FUNCTION
db=# create table m (f1 int, f2 int, primary key(f1,f2));
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "m_pkey" for table "m"
CREATE TABLE
db=# create table s (r1 int, r2 int, foreign key (r2,r1) references m);
CREATE TABLE
db=# select conrelid::regclass,conname from pg_constraint where contype = 'f'
and not exists (select 1 from pg_index where indrelid=conrelid and sortarray(conkey) = sortarray(indkey));
conrelid | conname
----------+-----------
s | s_r2_fkey
(1 row)
db=# create index si on s(r1,r2);
CREATE INDEX
db=# select conrelid::regclass,conname from pg_constraint where contype = 'f'
and not exists (select 1 from pg_index where indrelid=conrelid and sortarray(conkey) = sortarray(indkey));
conrelid | conname
----------+---------
(0 rows)
Ugh :-(
regards, tom lane
From | Date | Subject | |
---|---|---|---|
Next Message | Garry Saddington | 2008-12-28 21:40:28 | timestamp differences |
Previous Message | Teemu Juntunen | 2008-12-28 18:22:30 | Re: Bind message has 6 results formats but query has 5 columns |