Permalink
Browse files

[1.5.X] Fixed #15361 - Documented performance considerations for Quer…

…ySet.get()

Thanks mmcnickle for the patch.

Backport of feaf9f2 from master
  • Loading branch information...
timgraham committed Nov 2, 2012
1 parent 6b1f731 commit ffc649df888ea35d0e6848bf53ee26917fccc27e
Showing with 70 additions and 1 deletion.
  1. +35 −0 docs/topics/db/optimization.txt
  2. +35 −1 tests/modeltests/basic/tests.py
@@ -132,6 +132,41 @@ Write your own :doc:`custom SQL to retrieve data or populate models
</topics/db/sql>`. Use ``django.db.connection.queries`` to find out what Django
is writing for you and start from there.
Retrieve individual objects using a unique, indexed column
==========================================================
There are two reasons to use a column with
:attr:`~django.db.models.Field.unique` or
:attr:`~django.db.models.Field.db_index` when using
:meth:`~django.db.models.query.QuerySet.get` to retrieve individual objects.
First, the query will be quicker because of the underlying database index.
Also, the query could run much slower if multiple objects match the lookup;
having a unique constraint on the column guarantees this will never happen.
So using the :ref:`example Weblog models <queryset-model-example>`::
>>> entry = Entry.objects.get(id=10)
will be quicker than:
>>> entry = Entry.object.get(headline="News Item Title")
because ``id`` is indexed by the database and is guaranteed to be unique.
Doing the following is potentially quite slow:
>>> entry = Entry.objects.get(headline__startswith="News")
First of all, `headline` is not indexed, which will make the underlying
database fetch slower.
Second, the lookup doesn't guarantee that only one object will be returned.
If the query matches more than one object, it will retrieve and transfer all of
them from the database. This penalty could be substantial if hundreds or
thousands of records are returned. The penalty will be compounded if the
database lives on a separate server, where network overhead and latency also
play a factor.
Retrieve everything at once if you know you will need it
========================================================
@@ -2,7 +2,7 @@
from datetime import datetime
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db.models.fields import Field, FieldDoesNotExist
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import six
@@ -128,6 +128,40 @@ def test_lookup(self):
b = Article.objects.get(pk=a.id)
self.assertEqual(a, b)
# Create a very similar object
a = Article(
id=None,
headline='Area man programs in Python',
pub_date=datetime(2005, 7, 28),
)
a.save()
self.assertEqual(Article.objects.count(), 2)
# Django raises an Article.MultipleObjectsReturned exception if the
# lookup matches more than one object
self.assertRaisesRegexp(
MultipleObjectsReturned,
"get\(\) returned more than one Article -- it returned 2!",
Article.objects.get,
headline__startswith='Area',
)
self.assertRaisesRegexp(
MultipleObjectsReturned,
"get\(\) returned more than one Article -- it returned 2!",
Article.objects.get,
pub_date__year=2005,
)
self.assertRaisesRegexp(
MultipleObjectsReturned,
"get\(\) returned more than one Article -- it returned 2!",
Article.objects.get,
pub_date__year=2005,
pub_date__month=7,
)
def test_object_creation(self):
# Create an Article.
a = Article(

0 comments on commit ffc649d

Please sign in to comment.