On Monday 21 December 2015 19:42:22 Anssi Kääriäinen wrote:
> The only generic way to check the constraints is to run through all
> tables and their constraints. The constraint check itself is a check
> that a matching row in a foreign table exists for each row of the
> checked table. This means that the check could take hours on large
> databases. In addition the check isn't safe against concurrency
> issues. I'm afraid that if we have a flag for this for atomic(), then
> users are going to think it is a good idea to run the check just in
> case.
>
We can handle that by naming the argument "lengthy_constraint_check" or some
such.
> We could add a documented API to check wanted models for foreign key
> constraint violations (.check_constraints(Model1, Model2) would be a
> likely API). Then lets just document that depending on the database
> this check can be slow. On some databases we can get away with SET
> CONSTRAINTS IMMEDIATE
> [
http://www.postgresql.org/docs/9.1/static/sql-set-constraints.html],
> which should be fast.
Then why don't we implement check_constraints() as
"SET CONSTRAINTS IMMEDIATE; SET CONSTRAINTS DEFERRED" on PG? That is
documented to only check outstanding changes in the transaction.
I am not sure about the performance implications on Oracle, but the Oracle
docs suggest "Making constraints immediate at the end of a transaction is a
way of checking whether COMMIT can succeed."[1]
As far as I know, neither MySql nor Sqlite support deferrable constraints.
FWIW, MSSQL does not support deferring as such -- it only supports explicitly
turning the constraints off and on; when you turn them on, you can choose
between "with check", which checks every single row in your db, and "with no
check", which allows corrupt data into your DB; this makes loading fixtures
excruciatingly slow (I believe Anssi was involved in a recent to improve this
recently).
> I do think DEFERRABLE INITIALLY IMMEDIATE constraints would make a lot
> of sense for what Django is doing with the constraints, that is we
> want to keep the constraints in check except in special cases.
> Unfortunately I can't see an easy way to switch constraints to
> INITIALLY IMMEDIATE mode due to backwards compat and migrations
> issues.
>
We could handle the migrations if deferrability with an attribute of a FK, I
think; we could then handle backwards compatibility with a deprecation cycle
forcing deferrability to be explicit and then, setting a new default. However,
I don't think the benefit here is worth the amount of code churn.
Shai.
[1]
https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_10003.htm