Skip to content

Instantly share code, notes, and snippets.

Created October 16, 2012 20:59
Show Gist options
  • Select an option

  • Save anonymous/3902015 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/3902015 to your computer and use it in GitHub Desktop.
Django 1.4.1 SQL Hints Patch
diff --git a/db/models/query.py b/db/models/query.py
index 44acadf..a241fbd 100644
--- a/db/models/query.py
+++ b/db/models/query.py
@@ -90,7 +90,7 @@ class QuerySet(object):
return len(self._result_cache)
def __iter__(self):
- if self._prefetch_related_lookups and not self._prefetch_done:
+ if hasattr(self, "_prefetch_related_lookups") and self._prefetch_related_lookups and not self._prefetch_done:
# We need all the results in order to be able to do the prefetch
# in one go. To minimize code duplication, we use the __len__
# code path which also forces this, and also does the prefetch
@@ -822,6 +822,14 @@ class QuerySet(object):
clone._db = alias
return clone
+ def with_hints(self, *args, **kwargs):
+ clone = self._clone()
+ for hint in args:
+ clone.query.add_hint(self.model, hint)
+ for model, hint in kwargs.items():
+ clone.query.add_hint(model, hint)
+ return clone
+
###################################
# PUBLIC INTROSPECTION ATTRIBUTES #
###################################
diff --git a/db/models/sql/compiler.py b/db/models/sql/compiler.py
index 6c516e2..ca319e6 100644
--- a/db/models/sql/compiler.py
+++ b/db/models/sql/compiler.py
@@ -517,13 +517,22 @@ class SQLCompiler(object):
# alias_map if they aren't in a join. That's OK. We skip them.
continue
alias_str = (alias != name and ' %s' % alias or '')
+ index_hint = ''
+
+ for model, hint in self.query.hints.items():
+ if model._meta.db_table == name:
+ index_hint = ' USE INDEX (%s)' % ', '.join(hint)
+ break
+
if join_type and not first:
- result.append('%s %s%s ON (%s.%s = %s.%s)'
- % (join_type, qn(name), alias_str, qn(lhs),
- qn2(lhs_col), qn(alias), qn2(col)))
+ part = '%s %s%s%s ON (%s.%s = %s.%s)' \
+ % (join_type, qn(name), alias_str, index_hint, qn(lhs),
+ qn2(lhs_col), qn(alias), qn2(col))
else:
connector = not first and ', ' or ''
- result.append('%s%s%s' % (connector, qn(name), alias_str))
+ part = '%s%s%s' % (connector, qn(name), alias_str)
+
+ result.append(part)
first = False
for t in self.query.extra_tables:
alias, unused = self.query.table_alias(t)
diff --git a/db/models/sql/query.py b/db/models/sql/query.py
index ce11716..59a7e9d 100644
--- a/db/models/sql/query.py
+++ b/db/models/sql/query.py
@@ -95,6 +95,7 @@ class Query(object):
alias_prefix = 'T'
query_terms = QUERY_TERMS
aggregates_module = base_aggregates_module
+ hints={}
compiler = 'SQLCompiler'
@@ -132,6 +133,7 @@ class Query(object):
self.select_for_update_nowait = False
self.select_related = False
self.related_select_cols = []
+ self.hints = {}
# SQL aggregate-related attributes
self.aggregates = SortedDict() # Maps alias -> SQL aggregate function
@@ -1794,6 +1796,10 @@ class Query(object):
if order_by:
self.extra_order_by = order_by
+ def add_hint(self, model, hints):
+ for hint in hints:
+ add_to_dict(self.hints, hint["model"], hint["hint"])
+
def clear_deferred_loading(self):
"""
Remove any fields from the deferred loading set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment