Hi Marti,
On Tuesday 22 April 2014 18:37:37 Marti Raudsepp wrote:
> On Thu, Mar 27, 2014 at 4:20 PM, Shai Berger <
sh...@platonix.com> wrote:
> > The relevant tests do a select-for-update to verify that the "for update"
> > clause is, indeed, added; and they happen to run in autocommit mode. They
> > fail because, under Oracle, in autocommit mode, the automatic commit
> > happens immediately after the command is executed -- and so, trying to
> > fetch the results fails for being done in a separate transaction.
>
> Yes, please!
>
As you might have noticed, this fix is already included in Django 1.6.3 & 1.7b2
(released yesterday) and in current master.
> While we're already breaking backwards compatibility of
> select_for_update() then I have another wish that would make it more
> useful: a plain "FOR UPDATE" locks rows from all referenced tables in
> the FROM/JOIN clauses. This has bad interactions with
> select_related().
>
We are limiting the breaking of backwards compatibility as much as we can.
(below reordered a bit)
>
> 1. In my view, select_related is mostly a hint to Django "I'm going to
> need data from these tables too". I find it counter-intuitive that it
> currently changes the behavior to lock all related rows too. For
> example, consider:
> Author.objects.select_for_update().select_related('country').filter(...)
>
> Adding the select_related causes countries to be locked too -- which
> unnecessarily limits concurrency and increases risk of deadlocks. The
> number of countries is probably much more limited than authors.
>
> Solution
> ========
>
> A: If the database supports it, select_for_update could by default
> only lock the base model and not select_related joins. Maybe it could
> take a list of columns/tables to lock as well, not sure how useful
> that would be.
>
In order to change the default behavior, we'd need a strong concensus around
your intuition; one which I am not at all sure exists. On the contrary, my
intuition is that people using select_related are generally aware of the form
of generated SQL, and should expect locking as the current code does.
Even if we had this concensus, we would probably be very hesitant about
breaking backwards compatibility. We only did so in the case of #22343 because
we had a strong suspicion (which has since been confirmed, privately) that
previous behavior was leading users to create data-corruption bugs.
> 2. In PostgreSQL, FOR UPDATE fails on tables that are LEFT JOINed with
> error "FOR UPDATE cannot be applied to the nullable side of an outer
> join"
> So if the Author.country foreign key is nullable, the above example
> always fails. Oracle and MySQL ignore these, so it's kind of a
> compatibility issue.
>
> Solution
> ========
>
> B: Write a special case for PostgreSQL to skip locking of LEFT JOINed
> tables. This behavior seems inconsistent, though.
>
I don't think skipping locks on PostgreSQL only is going to fly, either.
However,based on your report below, I think it might make sense to add an
argument to select_for_update() to specify (via relations, as in
select_related) the tables to avoid locking. Something along the lines of,
select_for_update(nowait=False, nolock=None)
and in your example above,
Author.objects.select_related('country').select_for_update(nolock=['country'])
Based on your review of support in backends, this could be implemented by
Postgres and Oracle; MySQL will not support this, just like it currently fails
to support the nowait argument.
Also note: Earlier in this thread, Anssi suggested a way to implement
select_for_update() for SQLite (locking the entire database -- that's what
SQLite does for every write). This may be added in the future -- of course,
implementing neither the existing nowait flag nor the proposed nolock.
Shai.