From 2bf452dde83c3b76837ede5f8f623463a4729a96 Mon Sep 17 00:00:00 2001 From: Dimitri Yatsenko Date: Fri, 31 Jul 2026 14:29:42 -0500 Subject: [PATCH] docs(#1512): specify FK-column indexing on PostgreSQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - table-declaration spec §2.6 (new): DataJoint guarantees FK columns are indexed on both backends — implicit on MySQL/InnoDB, emitted (coverage-aware) on PostgreSQL; skipped when already a left-prefix of the PK or a declared index. - database-backends spec: add the FK-index row to Backend-Specific Behavior with a pointer to the declaration spec. - referential-integrity explanation §5: flip the now-obsolete guidance to declare an explicit index on PostgreSQL; the database indexes FK columns on both backends. Pairs with datajoint-python #1526. --- src/explanation/referential-integrity.md | 13 ++++++++----- src/reference/specs/database-backends.md | 5 +++++ src/reference/specs/table-declaration.md | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/explanation/referential-integrity.md b/src/explanation/referential-integrity.md index 273e6216..870e4e53 100644 --- a/src/explanation/referential-integrity.md +++ b/src/explanation/referential-integrity.md @@ -105,13 +105,16 @@ quietly rewritten. ### 5. Indexing the foreign-key columns -On MySQL/InnoDB the engine automatically creates a secondary index on the -child's foreign-key columns as part of enforcing the constraint — you never +The child's foreign-key columns are always indexed, on both backends — you never declare it. Such an index accelerates the delete check (finding a parent's children), the join (matching child keys to parent keys), and the insert check -(confirming the parent exists). PostgreSQL does *not* index foreign-key columns -automatically; when the delete or join cost on a large child table matters, -declare an explicit `index(...)` on those columns. +(confirming the parent exists). On MySQL/InnoDB the engine creates the index +implicitly as part of enforcing the constraint. PostgreSQL does *not* index +foreign-key columns automatically, so DataJoint emits the index itself — skipping +it only when those columns are already covered (a left-prefix of the primary key +or of a declared index). Either way, the mental model holds: the database indexes +foreign-key columns. See the +[table-declaration spec](../reference/specs/table-declaration.md#26-foreign-key-indexes). ## The dual role: integrity and workflow diff --git a/src/reference/specs/database-backends.md b/src/reference/specs/database-backends.md index d25c3225..1b4dcf06 100644 --- a/src/reference/specs/database-backends.md +++ b/src/reference/specs/database-backends.md @@ -90,6 +90,11 @@ The following features work identically across all backends: | JSON operators | `->`, `->>` | `->`, `->>` | | BLOB storage | `LONGBLOB` | `BYTEA` | | Boolean type | `TINYINT(1)` | `BOOLEAN` | +| Foreign-key column index | Implicit (InnoDB) | Emitted by DataJoint (coverage-aware) | + +DataJoint guarantees foreign-key columns are indexed on both backends; the +difference above is only *who* creates the index. See +[Foreign-Key Indexes](table-declaration.md#26-foreign-key-indexes). ### String Quoting diff --git a/src/reference/specs/table-declaration.md b/src/reference/specs/table-declaration.md index ca68bfb0..6e62a516 100644 --- a/src/reference/specs/table-declaration.md +++ b/src/reference/specs/table-declaration.md @@ -130,6 +130,26 @@ Internally, singleton tables use a hidden `_singleton` attribute of type `bool` - Excluded from `fetch()` results - Excluded from join matching +### 2.6 Foreign-Key Indexes + +DataJoint guarantees that a foreign key's referencing (child) columns are +indexed, so foreign-key joins, cascade deletes, and the parent-existence check +are index-supported on every backend. + +- On **MySQL/InnoDB** the index is created implicitly as part of enforcing the + constraint; DataJoint declares nothing. +- On **PostgreSQL**, which does not index foreign-key columns automatically, + DataJoint emits the index itself. + +The emitted index is **coverage-aware**: it is skipped when the foreign-key +columns are already a left-prefix of an existing index — the table's primary key, +a declared `index(...)`/`unique index(...)`, or a wider foreign-key index — since +that index already serves the lookups. So a *leading* primary foreign key adds no +index, while a *secondary* foreign key or one in a *non-leading* position of a +composite primary key gets its own. A `unique` foreign key always carries its +`UNIQUE INDEX` on both backends. (Index lifecycle on foreign-key drop / `alter()` +is out of scope of declaration; see the schema-changes specification.) + --- ## 3. Attribute Definition