2011-02-01 25 views
22

Configuración:
Django 1.1.2, MySQL 5.1¿Cómo hacer Django QuerySet mayor delete() más eficiente

Problema:

Blob.objects.filter(foo = foo) \ 
      .filter(status = Blob.PLEASE_DELETE) \ 
      .delete() 

resultados este fragmento en el ORM generar primero una consulta SELECT * from xxx_blob where ..., luego haciendo un DELETE from xxx_blob where id in (BLAH); donde BLAH es una lista ridículamente larga de id's. Como estoy eliminando una gran cantidad de blobs, esto hace que tanto yo como DB estén muy descontentos.

¿Hay alguna razón para esto? No veo por qué el ORM no puede convertir el fragmento de arriba en una sola consulta DELETE. ¿Hay alguna forma de optimizar esto sin recurrir a SQL sin formato?

Respuesta

13

No sin escribir su propio SQL personalizado o administradores o algo así; sin embargo, aparentemente están trabajando en eso.

http://code.djangoproject.com/ticket/9519

+0

Esto es realmente desafortunado. Gracias por indicarme el boleto. – svintus

+1

El boleto brinda la razón por la que estabas buscando. No es del todo sin mérito. –

3

Bulk delete ya es parte de Django

+4

Queryset.delete() se comporta de la forma descrita por el OP. –

+1

Todavía es ineficiente y da como resultado 'OperationalError: (2006, 'El servidor MySQL se ha ido')' – Andrei

+0

A granel - en este contexto - significa que una consulta SQL liviana se ejecuta en el servidor en función de la condición WHERE. La función 'delete()' de Django ORM no actúa así. –

9

Para aquellos que todavía están en busca de una forma eficiente de mayor eliminar en Django, aquí es una solución posible:

La razón de eliminación() puede ser tan lento es doble: 1) django tiene que asegurarse de que las funciones de eliminación en cascada sean correctas, buscando así referencias de claves externas a sus modelos; 2) django tiene que manejar las señales de pre y post-guardado para sus modelos.

Si sabe que su modelos no tienen el borrado en cascada o señales que se manejan, se puede acelerar este proceso mediante el recurso a la _raw_delete API privada de la siguiente manera:

queryset._raw_delete(queryset.db) 

Más detalles en here. Tenga en cuenta que django ya intenta hacer un buen manejo de estos eventos, aunque usar la eliminación sin procesar es, en muchas situaciones, mucho más eficiente.

+0

Django puede hacer esto como una función pública de queryset como 'bulk_delete', no es así? ¿Por qué no está hecho? ¿Alguna razón de alto nivel? Y aquellos que usan 'bulk_create' son conscientes de que las señales no funcionarán. Puede ser solo para borrar en cascada? – Babu

+0

Esto funciona para mí. La advertencia principal que se menciona es la de los modelos dependientes ("eliminación en cascada"): siempre que sea la clase más alta de tablas sin dependencias, esto funciona y funciona muy rápido. – nickang

Cuestiones relacionadas