Added 'hint' support, telling Mongo the proper index to use for the query.
Judicious use of hints can greatly improve query performance. When doing a query on multiple fields (at least one of which is indexed) pass the indexed field as a hint to the query. Hinting will not do anything if the corresponding index does not exist. The last hint applied to this cursor takes precedence over all others. Closes #203
This commit is contained in:
		| @@ -5,6 +5,7 @@ Changelog | ||||
| Changes in dev | ||||
| ============== | ||||
|  | ||||
| - Added hint() support, so cantell Mongo the proper index to use for the query | ||||
| - Fixed issue with inconsitent setting of _cls breaking inherited referencing | ||||
| - Added help_text and verbose_name to fields to help with some form libs | ||||
| - Updated item_frequencies to handle embedded document lookups | ||||
|   | ||||
| @@ -347,6 +347,7 @@ class QuerySet(object): | ||||
|         self._cursor_obj = None | ||||
|         self._limit = None | ||||
|         self._skip = None | ||||
|         self._hint = -1  # Using -1 as None is a valid value for hint | ||||
|  | ||||
|     def clone(self): | ||||
|         """Creates a copy of the current :class:`~mongoengine.queryset.QuerySet`""" | ||||
| @@ -354,7 +355,7 @@ class QuerySet(object): | ||||
|  | ||||
|         copy_props = ('_initial_query', '_query_obj', '_where_clause', | ||||
|                     '_loaded_fields', '_ordering', '_snapshot', | ||||
|                     '_timeout', '_limit', '_skip', '_slave_okay') | ||||
|                     '_timeout', '_limit', '_skip', '_slave_okay', '_hint') | ||||
|  | ||||
|         for prop in copy_props: | ||||
|             val = getattr(self, prop) | ||||
| @@ -539,6 +540,9 @@ class QuerySet(object): | ||||
|             if self._skip is not None: | ||||
|                 self._cursor_obj.skip(self._skip) | ||||
|  | ||||
|             if self._hint != -1: | ||||
|                 self._cursor_obj.hint(self._hint) | ||||
|  | ||||
|         return self._cursor_obj | ||||
|  | ||||
|     @classmethod | ||||
| @@ -965,6 +969,21 @@ class QuerySet(object): | ||||
|         self._skip = n | ||||
|         return self | ||||
|  | ||||
|     def hint(self, index=None): | ||||
|         """Added 'hint' support, telling Mongo the proper index to use for the | ||||
|         query. | ||||
|  | ||||
|         Judicious use of hints can greatly improve query performance. When doing | ||||
|         a query on multiple fields (at least one of which is indexed) pass the | ||||
|         indexed field as a hint to the query. | ||||
|  | ||||
|         Hinting will not do anything if the corresponding index does not exist. | ||||
|         The last hint applied to this cursor takes precedence over all others. | ||||
|         """ | ||||
|         self._cursor.hint(index) | ||||
|         self._hint = index | ||||
|         return self | ||||
|  | ||||
|     def __getitem__(self, key): | ||||
|         """Support skip and limit using getitem and slicing syntax. | ||||
|         """ | ||||
|   | ||||
| @@ -513,7 +513,6 @@ class DocumentTest(unittest.TestCase): | ||||
|  | ||||
|         BlogPost.drop_collection() | ||||
|  | ||||
|  | ||||
|     def test_dictionary_indexes(self): | ||||
|         """Ensure that indexes are used when meta[indexes] contains dictionaries | ||||
|         instead of lists. | ||||
| @@ -546,6 +545,35 @@ class DocumentTest(unittest.TestCase): | ||||
|  | ||||
|         BlogPost.drop_collection() | ||||
|  | ||||
|     def test_hint(self): | ||||
|  | ||||
|         class BlogPost(Document): | ||||
|             tags = ListField(StringField()) | ||||
|             meta = { | ||||
|                 'indexes': [ | ||||
|                     'tags', | ||||
|                 ], | ||||
|             } | ||||
|  | ||||
|         BlogPost.drop_collection() | ||||
|  | ||||
|         for i in xrange(0, 10): | ||||
|             tags = [("tag %i" % n) for n in xrange(0, i % 2)] | ||||
|             BlogPost(tags=tags).save() | ||||
|  | ||||
|         self.assertEquals(BlogPost.objects.count(), 10) | ||||
|         self.assertEquals(BlogPost.objects.hint().count(), 10) | ||||
|         self.assertEquals(BlogPost.objects.hint([('tags', 1)]).count(), 10) | ||||
|  | ||||
|         self.assertEquals(BlogPost.objects.hint([('ZZ', 1)]).count(), 10) | ||||
|  | ||||
|         def invalid_index(): | ||||
|             BlogPost.objects.hint('tags') | ||||
|         self.assertRaises(TypeError, invalid_index) | ||||
|  | ||||
|         def invalid_index_2(): | ||||
|             return BlogPost.objects.hint(('tags', 1)) | ||||
|         self.assertRaises(TypeError, invalid_index_2) | ||||
|  | ||||
|     def test_unique(self): | ||||
|         """Ensure that uniqueness constraints are applied to fields. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user