2011-10-27 20 views
10

Sto cercando di creare un oggetto Activty per un elenco di dimensioni grandi (300+ alla volta) di oggetti Inquiry. Ho un singolo ModelForm che viene posticipato, e ho bisogno di creare istanze separate e collegarle al mio Inquiry tramite un GenericForeignKey. Veniamo al codice:Creare voci di database di massa in modo efficiente?

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() 

Quello che sto cercando è un modo per inserire questi nel database , preferibilmente in una sola passata in modo che la richiesta possa essere elaborata più velocemente. Preferisco non scendere al livello di database in quanto questa applicazione viene distribuita su più fornitori di database, ma se questo è l'unico modo per procedere, così sia (gli esempi per MySQL e Postgres sarebbe fantastico).


Nota: So che c'è un bulk_create nella versione di sviluppo, ma che è fuori discussione finché non ci sarà una versione stabile.

risposta

3

Hai provato semplicemente a racchiudere il tuo for in un costrutto di transazione? Le transazioni commit-on-success possono ottenere enormi accelerazioni perché le voci vengono scritte in modo concreto sul disco contemporaneamente, quindi il DBMS non deve fermarsi per fsync() dopo ogni elemento.

operazioni esecutive nelle versioni recenti di Django è scattanti, controlla https://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views

+0

Sembra una buona idea, ma non ha cambiato molto le prestazioni. In 5-10 Attività, ha avuto un aumento della velocità del 5% circa. Su 100, una diminuzione della velocità del 10%. –

+0

Grazie per il puntatore. Questa è una grande novità. – AgDude

0

si può essere in grado di ottenere alcuni suggerimenti (anche per diversi sistemi DB), cercando al Django sql genera per alcuni dati di esempio. eseguendo il server in modalità di debug tutte le query vengono registrate. è anche possibile controllare tramite

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

Date un'occhiata a http://people.iola.dk/olau/python/bulkops.py

Fornisce funzioni insert_many e update_many che eseguono una singola query. Come notato dall'autore, dovrai eseguire un po 'di contabilità manuale in python per pks in molte e molte relazioni, ma una volta che hai risolto il problema, puoi semplicemente eseguire un paio di insert_many su Inquiry e InquiryEntry.

0

Questo non rende la vostra azione di massa più efficiente, ma se un Inquiry non ha bisogno di essere risposto istantaneamente in base ai dati inviati (sto assumendo in base al nome del modello), questo suona come il perfetto lavoro per una coda di attività come Celery.

L'utente otterrà una risposta super veloce e gli operatori del vostro sedano potranno crearlo a loro piacimento. Quando 1.4 è stabile, controlla in_bulk :)

Sarei interessato anche a un metodo di roccia solido agnostico, ma a seconda della situazione questa potrebbe essere una soluzione accettabile.

starà a guardare risposte qui ...

Problemi correlati