> 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:

```pgsql
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:

- [How to list table foreign keys][1]

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:

```pgsql
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 ...

  [1]: https://stackoverflow.com/a/1154078/939860