60 lines
1.6 KiB
Markdown
60 lines
1.6 KiB
Markdown
---
|
|
title: Index Foreign Key Columns
|
|
impact: HIGH
|
|
impactDescription: 10-100x faster JOINs and CASCADE operations
|
|
tags: foreign-key, indexes, joins, schema
|
|
---
|
|
|
|
## Index Foreign Key Columns
|
|
|
|
Postgres does not automatically index foreign key columns. Missing indexes cause slow JOINs and CASCADE operations.
|
|
|
|
**Incorrect (unindexed foreign key):**
|
|
|
|
```sql
|
|
create table orders (
|
|
id bigint generated always as identity primary key,
|
|
customer_id bigint references customers(id) on delete cascade,
|
|
total numeric(10,2)
|
|
);
|
|
|
|
-- No index on customer_id!
|
|
-- JOINs and ON DELETE CASCADE both require full table scan
|
|
select * from orders where customer_id = 123; -- Seq Scan
|
|
delete from customers where id = 123; -- Locks table, scans all orders
|
|
```
|
|
|
|
**Correct (indexed foreign key):**
|
|
|
|
```sql
|
|
create table orders (
|
|
id bigint generated always as identity primary key,
|
|
customer_id bigint references customers(id) on delete cascade,
|
|
total numeric(10,2)
|
|
);
|
|
|
|
-- Always index the FK column
|
|
create index orders_customer_id_idx on orders (customer_id);
|
|
|
|
-- Now JOINs and cascades are fast
|
|
select * from orders where customer_id = 123; -- Index Scan
|
|
delete from customers where id = 123; -- Uses index, fast cascade
|
|
```
|
|
|
|
Find missing FK indexes:
|
|
|
|
```sql
|
|
select
|
|
conrelid::regclass as table_name,
|
|
a.attname as fk_column
|
|
from pg_constraint c
|
|
join pg_attribute a on a.attrelid = c.conrelid and a.attnum = any(c.conkey)
|
|
where c.contype = 'f'
|
|
and not exists (
|
|
select 1 from pg_index i
|
|
where i.indrelid = c.conrelid and a.attnum = any(i.indkey)
|
|
);
|
|
```
|
|
|
|
Reference: [Foreign Keys](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK)
|