[1.8.x] Fixed #23372 -- Made loaddata faster if it doesn't find any fixtures.

Django's test suite often tries to load fixture files from apps that have
no fixtures at all. This creates a lot of unnecessary disabling and
enabling of constraints which can be expensive on some database.

To speed this up, loaddata now first checks if any fixture file matches.
If no fixture file is matched, then the command exits before disabling
and enabling of constraints is done.

The main benefit of this change is seen on MSSQL, where tests on
Django 1.8 run hours faster.

Backport of ee9f4686b1 from master
This commit is contained in:
Anssi Kääriäinen 2015-12-29 18:29:11 +02:00 committed by Tim Graham
parent cef1bc87f9
commit 1261c49690
3 changed files with 26 additions and 1 deletions

View File

@ -85,6 +85,16 @@ class Command(BaseCommand):
if has_bz2:
self.compression_formats['bz2'] = (bz2.BZ2File, 'r')
# Django's test suite repeatedly tries to load initial_data fixtures
# from apps that don't have any fixtures. Because disabling constraint
# checks can be expensive on some database (especially MSSQL), bail
# out early if no fixtures are found.
for fixture_label in fixture_labels:
if self.find_fixtures(fixture_label):
break
else:
return
with connection.constraint_checks_disabled():
for fixture_label in fixture_labels:
self.load_label(fixture_label)

View File

@ -51,3 +51,6 @@ Bugfixes
* Fixed a regression in the admin which ignored line breaks in read-only fields
instead of converting them to ``<br>`` (:ticket:`25465`).
* Made ``loaddata`` skip disabling and enabling database constraints when it
doesn't load any fixtures (:ticket:`23372`).

View File

@ -9,7 +9,7 @@ from django.contrib.sites.models import Site
from django.core import management
from django.db import IntegrityError, connection
from django.test import (
TestCase, TransactionTestCase, ignore_warnings, skipUnlessDBFeature,
TestCase, TransactionTestCase, ignore_warnings, mock, skipUnlessDBFeature,
)
from django.utils import six
from django.utils.encoding import force_text
@ -417,6 +417,18 @@ class NonExistentFixtureTests(TestCase):
management.call_command('loaddata', 'initial_data.json', verbosity=0)
self.assertEqual(len(w), 0)
@mock.patch('django.db.connection.enable_constraint_checking')
@mock.patch('django.db.connection.disable_constraint_checking')
def test_nonexistent_fixture_no_constraint_checking(self,
disable_constraint_checking, enable_constraint_checking):
"""
If no fixtures match the loaddata command, constraints checks on the
database shouldn't be disabled. This is performance critical on MSSQL.
"""
management.call_command('loaddata', 'this_fixture_doesnt_exist', verbosity=0)
disable_constraint_checking.assert_not_called()
enable_constraint_checking.assert_not_called()
class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):