2011-10-27 8 views
10

Estoy tratando de crear un objeto Activty para una lista grande (más de 300 a la vez) de objetos Inquiry. Tengo un único ModelForm que se está publicando, y necesito crear instancias separadas, y adjuntarlas a mi Inquiry a través de GenericForeignKey. Vamos a llegar a un cierto código:Crear entradas de bases de datos masivas de manera eficiente?

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

Lo que estoy buscando es una manera de insertar estos en la base de datos , preferiblemente en una sola pasada para que la solicitud se pueda procesar más rápido. Prefiero no bajar al nivel de la base de datos ya que esta aplicación se implementa en múltiples proveedores de bases de datos, pero si esa es la única forma de proceder, que así sea (ejemplos para MySQL y Postgres serían increíbles).


Nota: Sé que hay un bulk_create en la versión de desarrollo, pero que está fuera de la cuestión hasta que haya una versión estable.

Respuesta

3

¿Intentó simplemente encerrar su for en una construcción de transacción? Las transacciones de compromiso en el éxito pueden generarle aceleraciones masivas debido a que las entradas se escriben concretamente en el disco al por mayor, por lo que el DBMS no tiene que detenerse para fsync() después de cada elemento.

transacciones de aplicación en las últimas versiones de Django es ágil, echa un vistazo a https://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views

+0

Parece una buena idea, pero no cambió mucho el rendimiento. En 5-10 Actividades, tuvo un aumento de velocidad de aproximadamente 5%. En 100, una disminución del 10% de velocidad. –

+0

Gracias por el puntero. Esta es una gran nueva característica. – AgDude

0

usted puede ser capaz de obtener algunas pistas (incluyendo por diferentes sistemas db) mirando el Django genera SQL para algunos datos de la muestra. ejecutando su servidor en modo de depuración se registran todas las consultas. también se puede inspeccionar a través de

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

Tome un vistazo a http://people.iola.dk/olau/python/bulkops.py

Proporciona funciones insert_many y update_many que ejecutan una sola consulta. Como señaló el autor, tendrá que hacer una contabilidad manual en python para pks en muchas relaciones, pero una vez que las haya resuelto, puede simplemente ejecutar par de insert_many en Inquiry y InquiryEntry.

0

Esto no hace que su acción masiva sea más eficiente, pero si un Inquiry no necesita respuesta instantánea en base a los datos enviados (supongo que en función del nombre del modelo), esto suena como el perfecto trabajo para una cola de tareas como Apio.

El usuario obtendrá una respuesta súper rápida, y los trabajadores del apio pueden atravesarla cuando lo desee. Cuando 1.4 es estable, consulte in_bulk :)

También me interesaría un método de roca sólida independiente de la base de datos pero, dependiendo de su situación, esta podría ser una solución aceptable.

respuestas

estarán atentos aquí ...

Cuestiones relacionadas