2010-08-03 16 views
31

Estoy usando Django con un back-end sqlite, y el rendimiento de escritura es un problema. Puedo graduarme a un DB "apropiado" en algún momento, pero por el momento estoy atascado con sqlite. Creo que mis problemas de rendimiento de escritura están probablemente relacionados con el hecho de que estoy creando una gran cantidad de filas, y presumiblemente, cada vez que save() está bloqueando, desbloqueando y sincronizando la base de datos en el disco.Agregando save() s en Django?

¿Cómo puedo agregar un gran número de llamadas save() en una única operación de base de datos?

+0

http://stackoverflow.com/questions/1136106/efficent-way-to-insert-thousands-of-records-into-a-table-sqlite-python-django –

+0

@Tomasz - gracias por el enlace, el @commit_manually decorator me da la mejora de rendimiento que necesito. He marcado mi pregunta para el cierre como un engaño porque creo que la otra lo cubre bastante bien. – kdt

+0

En realidad, puede cerrar su pregunta en lugar de simplemente votar por el cierre, ya sabe. –

Respuesta

54

En realidad, esto es más fácil de hacer, entonces piensas. Puede usar transactions en Django. Estas operaciones de base de datos por lotes (específicamente guardar, insertar y eliminar) en una sola operación. Encontré el más fácil de usar es commit_on_success. Esencialmente envuelve las operaciones de guardar de la base de datos en una función y luego utiliza el decorador commit_on_success.

from django.db.transaction import commit_on_success 

@commit_on_success 
def lot_of_saves(queryset): 
    for item in queryset: 
     modify_item(item) 
     item.save() 

Esto tendrá un gran aumento de velocidad. También obtendrá la ventaja de tener reversiones si alguno de los elementos falla. Si tiene millones de operaciones de guardado, es posible que deba enviarlas en bloques usando commit_manually y transaction.commit(), pero rara vez las necesito.

Espero que ayude,

Will

+0

Esto fue casi mágico. Envolví una función aleatoria que crea una gran cantidad de registros, y se convirtió instantáneamente varias veces más rápido en SQLite. – alberge

+32

Para aquellos de ustedes que se encuentren con esta respuesta ahora, 'commit_on_success' ahora está en desuso. En cambio, reemplázalo con 'atomic', que es la nueva versión y tendrá el mismo efecto mágico. – Pterosaur

+7

referencia 'atomic': https://docs.djangoproject.com/en/dev/topics/db/transactions/#django.db.transaction.atomic – Paolo

1

"¿Cómo puedo agregar un gran número de llamadas a save() en una sola operación de base de datos?"

No es necesario. Django ya administra un caché para ti. No se puede mejorar el almacenamiento en caché DB al tratar de preocuparse por los guardados.

"problemas de rendimiento de escritura están probablemente relacionados con el hecho de que estoy creando un gran número de filas"

correcta.

SQLite es bastante lento. Esa es la forma en que está. Las consultas son más rápidas que la mayoría de otras DB. Las escrituras son bastante lentas

Considere un cambio de arquitectura más serio. ¿Está cargando filas durante una transacción web (es decir, cargando archivos a granel y cargando el DB desde esos archivos)?

Si realiza una carga masiva dentro de una transacción web, deténgase. Debes hacer algo más inteligente. Use celery o use alguna otra función "por lotes" para hacer sus cargas en segundo plano.

Intentamos limitarnos a la validación de archivos en una transacción web y hacer las cargas cuando el usuario no está esperando su página de HTML.

+1

Aunque es justo señalar que sqlite es inherentemente lento en las escrituras debido a la forma en que usa el disco, no tiene que ser * esto * lento: según lo sugerido por un comentarista, comencé a usar el decorador @commit_manually y encontré una mejora realmente sustancial. – kdt

41

nuevos a partir de Django 1.6 es atomic, a simple API to control DB transactions.Una copia literal de los documentos:

atómica es utilizable tanto como decorator:

from django.db import transaction 

@transaction.atomic 
def viewfunc(request): 
    # This code executes inside a transaction. 
    do_stuff() 

y como context manager:

from django.db import transaction 

def viewfunc(request): 
    # This code executes in autocommit mode (Django's default). 
    do_stuff() 

    with transaction.atomic(): 
     # This code executes inside a transaction. 
     do_more_stuff() 

Legado django.db.transaction funciones autocommit(), commit_on_success() y commit_manually() han quedado en desuso y se eliminará en Django 1.8.

Cuestiones relacionadas