Skip to main content
typos
Source Link
Erwin Brandstetter
  • 182.2k
  • 28
  • 457
  • 620

It's OK for it to fail (and, for my logic, revert the whole transaction), but I don't want this failure to take 2ms instead of 40 seconds.

Running the actual DELETE query (with EXPLAIN ANALYZE wrapper or not) is considerably more expensive than checking with a SELECT whether any FK reference will prevent the operation.

Identify FK constraints pointing to your table:

SELECT c.conrelid::regclass::text AS referencing_table
     , pg_get_constraintdef(c.oid) AS fk
FROM   pg_constraint c
WHERE  c.confrelid = 'public.bigtype'::regclass
AND    c.contype  = 'f'
ORDER  BY 1, 2;

See:

You get 0-n rows of the form:

referencing_tbl | FOREIGN KEY (referencing_col, ...) REFERENCES matches(referenced_col, ...) ...

Based on this, the fastest possible query would be:

SELECT EXISTS (
   SELECT FROM matches m
   WHERE  WHERE id = 1
   AND   (EXISTS (SELECT FROM referencing_tbl t WHERE (t.referencing_col, ...) = (m.referenced_col, ...))
    -- OR EXISTS ... -- one predicate per FK
         )
   );

true ... At least one row is being referenced. DELETE will fail. 
false ... No references. DELETE will succeed.

Of course, if there isWith concurrent write access, there is a possible race condition. Probably unimportant for your case.

If your relational design is not stable, you might generate that SELECT query completely dynamically ...

It's OK for it to fail (and, for my logic, revert the whole transaction), but I don't want this failure to take 2ms instead of 40 seconds.

Running the actual DELETE query (with EXPLAIN ANALYZE wrapper or not) is considerably more expensive than checking with a SELECT whether any FK reference will prevent the operation.

Identify FK constraints pointing to your table:

SELECT c.conrelid::regclass::text AS referencing_table
     , pg_get_constraintdef(c.oid) AS fk
FROM   pg_constraint c
WHERE  c.confrelid = 'public.bigtype'::regclass
AND    c.contype  = 'f'
ORDER  BY 1, 2;

See:

You get 0-n rows of the form:

referencing_tbl | FOREIGN KEY (referencing_col, ...) REFERENCES matches(referenced_col, ...) ...

Based on this, the fastest possible query would be:

SELECT EXISTS (
   SELECT FROM matches m
   WHERE  WHERE id = 1
   AND   (EXISTS (SELECT FROM referencing_tbl t WHERE (t.referencing_col, ...) = (m.referenced_col, ...))
    -- OR EXISTS ... -- one predicate per FK
         )
   );

true ... At least one row is being referenced. DELETE will fail. false ... No references. DELETE will succeed.

Of course, if there is concurrent write access, there is a possible race condition. Probably unimportant for your case.

If your relational design is not stable, you might generate that SELECT query completely dynamically ...

It's OK for it to fail (and, for my logic, revert the whole transaction), but I don't want this failure to take 2ms instead of 40 seconds.

Running the actual DELETE query (with EXPLAIN ANALYZE wrapper or not) is considerably more expensive than checking with a SELECT whether any FK reference will prevent the operation.

Identify FK constraints pointing to your table:

SELECT c.conrelid::regclass::text AS referencing_table
     , pg_get_constraintdef(c.oid) AS fk
FROM   pg_constraint c
WHERE  c.confrelid = 'public.bigtype'::regclass
AND    c.contype  = 'f'
ORDER  BY 1, 2;

See:

You get 0-n rows of the form:

referencing_tbl | FOREIGN KEY (referencing_col, ...) REFERENCES matches(referenced_col, ...) ...

Based on this, the fastest possible query would be:

SELECT EXISTS (
   SELECT FROM matches m
   WHERE  id = 1
   AND   (EXISTS (SELECT FROM referencing_tbl t WHERE (t.referencing_col, ...) = (m.referenced_col, ...))
    -- OR EXISTS ... -- one predicate per FK
         )
   );

true ... At least one row is being referenced. DELETE will fail. 
false ... No references. DELETE will succeed.

With concurrent write access, there is a possible race condition. Probably unimportant for your case.

If your relational design is not stable, you might generate that SELECT query completely dynamically ...

Source Link
Erwin Brandstetter
  • 182.2k
  • 28
  • 457
  • 620

It's OK for it to fail (and, for my logic, revert the whole transaction), but I don't want this failure to take 2ms instead of 40 seconds.

Running the actual DELETE query (with EXPLAIN ANALYZE wrapper or not) is considerably more expensive than checking with a SELECT whether any FK reference will prevent the operation.

Identify FK constraints pointing to your table:

SELECT c.conrelid::regclass::text AS referencing_table
     , pg_get_constraintdef(c.oid) AS fk
FROM   pg_constraint c
WHERE  c.confrelid = 'public.bigtype'::regclass
AND    c.contype  = 'f'
ORDER  BY 1, 2;

See:

You get 0-n rows of the form:

referencing_tbl | FOREIGN KEY (referencing_col, ...) REFERENCES matches(referenced_col, ...) ...

Based on this, the fastest possible query would be:

SELECT EXISTS (
   SELECT FROM matches m
   WHERE  WHERE id = 1
   AND   (EXISTS (SELECT FROM referencing_tbl t WHERE (t.referencing_col, ...) = (m.referenced_col, ...))
    -- OR EXISTS ... -- one predicate per FK
         )
   );

true ... At least one row is being referenced. DELETE will fail. false ... No references. DELETE will succeed.

Of course, if there is concurrent write access, there is a possible race condition. Probably unimportant for your case.

If your relational design is not stable, you might generate that SELECT query completely dynamically ...