| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
PostgreSQL never auto-indexes a foreign key's referencing (child) columns and offers no server setting to change that, so non-unique FKs were left unindexed — a performance cliff on cascades/joins and an asymmetry with MySQL/InnoDB. declare.py now emits an explicit index on the FK columns on the PostgreSQL DDL path, coverage-aware: skip when the FK columns are already a left-prefix of the child's primary key (a leading primary FK, served by the PK index), emit otherwise (secondary FKs and non-leading primary FKs). MySQL keeps InnoDB's implicit index; the unique-FK case keeps its UNIQUE INDEX. Creation only — FK-drop/alter lifecycle deferred. Tests (PostgreSQL-specific; verified failing without the fix).
The inline check only compared against the primary key (and couldn't see indexes declared after the FK line). Move the decision to a post-parse pass in prepare_declare, where the full primary key and index list are known: emit an FK support index unless its columns are a left-prefix of the primary key, of a declared index, or of a longer FK-support index already emitted (longest-first). compile_foreign_key now only records candidates. Never under-indexes; no longer creates redundant indexes. Adds a test for the declared-index coverage case.
Replace the `adapter.backend == "postgresql"` string check in declare.py with a new adapter capability, `auto_indexes_foreign_keys` (MySQL True, PostgreSQL False), mirroring `supports_inline_indexes`. The backend *policy* (who indexes FK columns) now lives on the adapter; the coverage/redundancy logic stays in declare.py as backend-agnostic schema-structure reasoning. Scales to new backends without touching declare.py.
| Back | FazBrowse Home | New Git URL |
Closes #1512.
Why
PostgreSQL never auto-indexes a foreign key's referencing (child) columns and offers no server setting to change it — only MySQL/InnoDB does, implicitly. So on Postgres a non-unique FK was left with no supporting index, a performance cliff for cascade deletes, joins on the FK, and parent-existence checks on large child tables — and an asymmetry with MySQL.
What
declare.py's compile_foreign_key() now emits an explicit index on the FK columns on the PostgreSQL DDL path only, coverage-aware:
The coverage test is exactly primary_key[:len(fk_attrs)] == fk_attrs. MySQL continues to rely on InnoDB's implicit index (nothing emitted); the unique FK case keeps its UNIQUE INDEX on both backends. The existing Postgres DDL path already converts INDEX (...) entries to CREATE INDEX statements, so no new plumbing.
Per the issue decision: index creation only — the index lifecycle on FK drop / .alter() is deferred to the schema-changes design.
Tests
tests/integration/test_fk_index.py (PostgreSQL-specific; MySQL cases skip since the index is InnoDB's, not ours):
Verified failing without the fix (negative control: the two positive tests fail) and passing with it; full test_declare.py + test_cascade_delete.py green on MySQL 8.0 and PostgreSQL 15 (52 passed, no regressions).
Follow-up (not in this PR)
datajoint-docs #227 currently advises users to declare an explicit index(...) on Postgres; once this lands, that guidance flips back to "the database indexes FK columns." I'll pair the docs update with the spec reshape.
Draft pending review.