Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Made some types of nested update queries very slightly more efficient…

… at the

database level. Also worked around the fact that MySQL (and maybe other
backends we don't know about) cannot select from the table they're updating.

Fixed #7095.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7496 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit ba010ec1c04c4832d42b088b092df0969afdb7e6 1 parent ff6e529
Malcolm Tredinnick malcolmt authored
1  django/db/backends/__init__.py
View
@@ -51,6 +51,7 @@ class BaseDatabaseFeatures(object):
uses_case_insensitive_names = False
uses_custom_query_class = False
empty_fetchmany_value = []
+ update_can_self_select = True
class BaseDatabaseOperations(object):
"""
1  django/db/backends/mysql/base.py
View
@@ -63,6 +63,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
autoindexes_primary_keys = False
inline_fk_references = False
empty_fetchmany_value = ()
+ update_can_self_select = False
class DatabaseOperations(BaseDatabaseOperations):
def date_extract_sql(self, lookup_type, field_name):
1  django/db/backends/mysql_old/base.py
View
@@ -67,6 +67,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
autoindexes_primary_keys = False
inline_fk_references = False
empty_fetchmany_value = ()
+ update_can_self_select = False
class DatabaseOperations(BaseDatabaseOperations):
def date_extract_sql(self, lookup_type, field_name):
23 django/db/models/sql/subqueries.py
View
@@ -159,20 +159,37 @@ def pre_sql_setup(self):
# from other tables.
query = self.clone(klass=Query)
query.bump_prefix()
- query.select = []
query.extra_select = {}
- query.add_fields([query.model._meta.pk.name])
+ first_table = query.tables[0]
+ if query.alias_refcount[first_table] == 1:
+ # We can remove one table from the inner query.
+ query.unref_alias(first_table)
+ for i in xrange(1, len(query.tables)):
+ table = query.tables[i]
+ if query.alias_refcount[table]:
+ break
+ join_info = query.alias_map[table]
+ query.select = [(join_info[RHS_ALIAS], join_info[RHS_JOIN_COL])]
+ must_pre_select = False
+ else:
+ query.select = []
+ query.add_fields([query.model._meta.pk.name])
+ must_pre_select = not self.connection.features.update_can_self_select
# Now we adjust the current query: reset the where clause and get rid
# of all the tables we don't need (since they're in the sub-select).
self.where = self.where_class()
- if self.related_updates:
+ if self.related_updates or must_pre_select:
+ # Either we're using the idents in multiple update queries (so
+ # don't want them to change), or the db backend doesn't support
+ # selecting from the updating table (e.g. MySQL).
idents = []
for rows in query.execute_sql(MULTI):
idents.extend([r[0] for r in rows])
self.add_filter(('pk__in', idents))
self.related_ids = idents
else:
+ # The fast path. Filters and updates in one query.
self.add_filter(('pk__in', query))
for alias in self.tables[1:]:
self.alias_refcount[alias] = 0
Please sign in to comment.
Something went wrong with that request. Please try again.