2009-12-28 15 views
10

Estoy creando un servicio que necesita para mantener algo en la línea de un sistema de seguimiento de casos. Aquí es nuestro modelo:rendimiento de django al consultar modelos con muchas claves externas?

class Incident(models.Model):  
    title = models.CharField(max_length=128) 
    category = models.ForeignKey(Category) 
    status = models.ForeignKey(Status)  
    severity = models.ForeignKey(Severity) 
    owned_by = models.ForeignKey(User, related_name="owned_by", null=True, blank=True) 
    next_action = models.ForeignKey(IncidentAction)  
    created_date = models.DateTimeField() 
    created_by = models.ForeignKey(User, related_name="opened_by")  
    last_edit_date = models.DateTimeField(null=True, blank=True) 
    last_edit_by = models.ForeignKey(User, related_name="last_edit_by", null=True, blank=True)   
    closed_date = models.DateTimeField(null=True, blank=True) 
    closed_by = models.ForeignKey(User, related_name="Closed by", null=True, blank=True) 

Debido a que hay una gran cantidad de claves externas que se tira en este modelo, lo hace para consultas SQL interesantes. Hemos estado utilizando como prueba el djblets data grid y la barra de herramientas de depuración django, y estamos alarmados por la cantidad de consultas que se golpean cada vez que agregamos una nueva columna para ver que usa una clave externa, básicamente hace este tipo de flujo de trabajo de consulta :

#prepare the grid 
select * from incident_table; 
#render each row 
for each row in incident table 
    for each column that is a foreign key select row from foreign table with id 

Se hace un consulta de selección adicional por fila para cada columna que intenta tirar de una propiedad de una clave externa.

Estoy pensando que este es un problema universal con django y su ORM con respecto a extraer propiedades de los modelos de clave externa para su visualización. Como prueba, dejé caer la cuadrícula de datos y acabo de hacer una lista simple de propiedades para un conjunto de consulta, y vi que las consultas aumentaban de forma similar.

Queremos ampliar esto con la gran cantidad de usuarios que utilizan el modelo. Como comparación, hice una vista similar del modelo de usuario, y su visualización completa se acaba de hacer con una consulta, porque si solo extraes campos del modelo dado, no se obtiene un hit de db adicional por columna adicional.

Algunas optimizaciones que probamos eran:

  • django-orm-cache: no parece trabajar con Django 1.0.4
  • django-caching: Esto funciona bien para el almacenamiento en caché el tantas veces preguntó modelos
  • vista caché de nivel memcached
  • Editar: usando select_related() puede acelerar la representación de la plantilla al no tener un viaje de ida y vuelta a la base de datos, pero parece que sigue las teclas foráneas solo una tiempo de espera en el conjunto de consulta original utilizando la única consulta por clave externa. Simplemente parece mover el resultado de la consulta de la base de datos múltiple antes de tiempo.

Pero hay algunas preguntas más profundas que estamos solicitando la sabiduría de la multitud:

  • Para los modelos con toneladas de claves externas, ¿cuál es la mejor manera de hacerlo de manera eficiente consulta para obtener propiedades de claves extranjeras?
    • ¿El almacenamiento en caché de los modelos dependientes es la única manera de utilizar los sistemas de caché ORM anteriores?
    • ¿O se trata de un caso estándar de crecimiento del ORM y la necesidad de lanzar nuestra propia consulta SQL personalizada con combinaciones para obtener la salida de cuadrícula de datos deseada de la manera más eficiente posible?

preguntas relacionadas que aumentaron las preocupaciones sobre el almacenamiento en caché y las claves externas:

DB/performance: layout of django model that rarely refers to its parent more than once, Django ORM: caching and manipulating ForeignKey objects:

Respuesta

11

select_related() es la solución correcta; te equivocas acerca de cómo se supone que debe funcionar. Creo que no está utilizando select_related correctamente si todavía está recibiendo múltiples consultas en el FK especificado. Un registro rápido de una sesión de Python (Estudio tiene una FK a django.auth.user aquí):

>>> from django.db import connection 
>>> studios = Studio.objects.all().select_related('user') 
>>> for studio in studios: 
>>>  print studio.user.email 
>>>   
[email protected] 
[email protected] 
>>> len(connection.queries) 
1 

lo tanto, tengo una lista de objetos de estudio (2 en mi prueba de DB) y dieron el usuario para cada Consulta SQL uno a uno. Sin la llamada select_related(), toma tres consultas.

Tenga en cuenta que select_related doesn't handle many-to-many relationships - aunque creo que puede consultar manualmente la tabla intermedia de la m2m para seguir esas FK en cualquier dirección sin requerir la consulta adicional, siempre y cuando esté bien comenzando su queryset desde el objeto intermedio. Tal vez eso es lo que te atrapa? Solo especificó relaciones FK, no m2ms, así que le di una ilustración simple de eso.

+0

Ah, sí. Me encuentro muy corregido: parece que la cuadrícula de datos está ignorando las optimizaciones proporcionadas por el conjunto de firmas proporcionado y realiza sus propias búsquedas. Las pruebas independientes de mi modelo con su ejemplo hicieron que los beneficios de select_related() fueran tan claros como el día. ¡Gracias! – dmyung

Cuestiones relacionadas