Maak bulk-database-entries efficiënt?

Ik probeer een Activty -object te maken voor een grote (300+ tegelijk) lijst met Navraag -objecten. Ik heb een enkele ModelForm die wordt teruggeplaatst en ik moet afzonderlijke exemplaren maken en deze koppelen aan mijn Onderzoek via een GenericForeignKey . Laten we naar een code gaan:

models.py:

class InquiryEntry(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField() 
    entry = generic.GenericForeignKey('content_type', 'object_id')

class Inquiry(models.Model):
    entries = models.ManyToManyField('InquiryEntry')
    # And many more fields.
    def add_entry(self, obj):
        entry = self.entries.create(entry=obj)
        self.save()
        return entry

class Activity(models.Model):  
    ts = models.DateTimeField(auto_now_add=True)                  
    due_date = models.DateField(auto_now=False)
    ## And many more fields.

views.py:

def bulk_create_activities(request):
    activity_form = ActivityForm()
    if request.method == "POST":
        activity_form = ActivityForm(request.POST)
        if activity_form.is_valid():    
            pks = [int(x) for x in request.POST.get('pks', '').split(',')]
            for inquiry in Inquiry.objects.filter(pk__in=pks):
                instance = ActivityForm(request.POST).save()
                inquiry.add_entry(instance)     
                inquiry.save()  

Wat ik zoek is een manier om deze in de database in te voegen, bij voorkeur in één keer, zodat het verzoek sneller kan worden verwerkt. Ik ga liever niet naar het databaseniveau omdat deze toepassing wordt geïmplementeerd in meerdere database-leveranciers, maar als dat de enige manier is om verder te gaan, dan is het goed (voorbeelden voor MySQL en Postgres zouden geweldig zijn).


Note: I know that there is a bulk_create in the development version, but that is out of the question until there is a stable release.

10

5 antwoord

Heb je geprobeerd om je voor in een transactieconstruct te plaatsen? Commit-on-success-transacties kunnen enorme snelheden opleveren, omdat items in bulk in bulk in bulk worden geschreven, dus de DBMS hoeft niet te stoppen voor fsync() na elk item.

Implementing transactions in recent versions of django is snappy, check out https://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views

3
toegevoegd
Lijkt een goed idee, maar heeft de prestaties niet erg veranderd. Op 5-10 activiteiten had het een snelheidstoename van ongeveer 5%. Op 100 neemt een snelheid van 10% af.
toegevoegd de auteur Jack M., de bron
Bedankt voor de aanwijzer. Dit is een geweldige nieuwe functie.
toegevoegd de auteur AgDude, de bron

Ik ben bang dat je moet laten vallen naar DB-API en gebruik cursor.executemany (). Zie PEP 249 voor meer informatie.

1
toegevoegd

Dit maakt uw bulkactie niet efficiënter, maar als een onderzoek niet onmiddellijk hoeft te worden beantwoord op basis van de ingediende gegevens (ik veronderstel dat deze gebaseerd is op de modelnaam), klinkt dit zoals het perfecte werk voor een wachtrij zoals Celery.

De gebruiker krijgt een supersnelle reactie en je selderijwerkers kunnen er op hun gemak mee knoeien. Als 1.4 stabiel is, bekijk dan in_bulk :)

Ik zou ook geïnteresseerd zijn in een database agnostic rock solid-methode, maar afhankelijk van uw situatie kan dit een acceptabele oplossing zijn.

Zal hier antwoorden vinden ...

0
toegevoegd

Take a look at http://people.iola.dk/olau/python/bulkops.py

Het biedt insert_many en update_many functies die een enkele query uitvoeren. Zoals opgemerkt door de auteur zult u een handmatige boekhouding in python moeten uitvoeren voor pks in vele tot vele relaties, maar als u eenmaal hebt uitgewerkt, kunt u eenvoudig enkele insert_many's uitvoeren op Enquiry en InquiryEntry .

0
toegevoegd

je kunt mogelijk enkele hints krijgen (ook voor verschillende db-systemen) door te kijken naar de SQL-django genereert voor sommige voorbeeldgegevens. Als u uw server in de foutopsporingsmodus uitvoert, worden alle query's vastgelegd. je kunt ze ook via inspecteren

>>> from django.db import connection
>>> connection.queries
0
toegevoegd