#33759: Using subquery to filter a model delete generates a sub-optimal SQL
-------------------------------------+-------------------------------------
     Reporter:  Christofer Bertonha  |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |
    Component:  Database layer       |                  Version:  4.0
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

 * stage:  Unreviewed => Accepted


Comment:

 We could add a new feature flag to add an extra subquery only on MySQL:
 {{{#!diff
 diff --git a/django/db/backends/base/features.py
 b/django/db/backends/base/features.py
 index c54d30cf73..e8737aadc2 100644
 --- a/django/db/backends/base/features.py
 +++ b/django/db/backends/base/features.py
 @@ -12,6 +12,9 @@ class BaseDatabaseFeatures:
      allows_group_by_selected_pks = False
      empty_fetchmany_value = []
      update_can_self_select = True
 +    # Does the backend support self-reference subqueries in the DELETE
 +    # statement?
 +    delete_can_self_reference_subquery = True

      # Does the backend distinguish between '' and None?
      interprets_empty_strings_as_nulls = False
 diff --git a/django/db/backends/mysql/features.py
 b/django/db/backends/mysql/features.py
 index 3ea3deeae3..848d891a84 100644
 --- a/django/db/backends/mysql/features.py
 +++ b/django/db/backends/mysql/features.py
 @@ -25,6 +25,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
      supports_slicing_ordering_in_compound = True
      supports_index_on_text_field = False
      supports_update_conflicts = True
 +    delete_can_self_reference_subquery = False
      create_test_procedure_without_params_sql = """
          CREATE PROCEDURE test_procedure ()
          BEGIN
 diff --git a/django/db/models/sql/compiler.py
 b/django/db/models/sql/compiler.py
 index 9c7bd8ea1a..e57a43ac47 100644
 --- a/django/db/models/sql/compiler.py
 +++ b/django/db/models/sql/compiler.py
 @@ -1721,7 +1721,10 @@ class SQLDeleteCompiler(SQLCompiler):
          Create the SQL for this query. Return the SQL string and list of
          parameters.
          """
 -        if self.single_alias and not
 self.contains_self_reference_subquery:
 +        if self.single_alias and (
 +            self.connection.features.delete_can_self_reference_subquery
 or
 +            not self.contains_self_reference_subquery
 +        ):
              return self._as_sql(self.query)
          innerq = self.query.clone()
          innerq.__class__ = Query
 }}}

 Another issue is that `QuerySet.delete()` from the ticket description:
 {{{
 subquery = Comment.objects.filter(created_at__lt=datetime(2022, 6,
 1))[:1000]
 Comment.objects.filter(id__in=subquery).delete()
 ...
   File "site-packages/MySQLdb/connections.py", line 254, in query
     _mysql.connection.query(self, query)
 django.db.utils.NotSupportedError: (1235, "This version of MySQL doesn't
 yet support 'LIMIT & IN/ALL/ANY/SOME subquery'")
 }}}
 crashes on MySQL even with 4074f38e1dcc93b859bbbfd6abd8441c3bca36b3.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33759#comment:5>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018122c0d8cd-ece375b4-40f9-4ddf-99c9-4053ab5b3c3b-000000%40eu-central-1.amazonses.com.

Reply via email to