relations queries prefetch_related optimize debug cache python database django performance

python - queries - Django: Incrementa el conteo de visitas de entrada de blog por uno. ¿Es esto eficiente?



django prefetch_related (5)

Revisado

Está actualizando 10 objetos separados, individuales y distintos.

Las 10 actualizaciones separadas, individuales y distintas no pueden colapsarse fácilmente en una actualización mágica que de alguna manera toca 10 objetos.

Tengo el siguiente código en mi vista de índice.

latest_entry_list = Entry.objects.filter(is_published=True).order_by(''-date_published'')[:10] for entry in latest_entry_list: entry.views = entry.views + 1 entry.save()

Si hay diez filas (el límite) devueltas desde la consulta inicial, ¿el problema de guardado tendrá 10 llamadas actualizadas separadas a la base de datos o Django es lo suficientemente "inteligente" para emitir solo una llamada de actualización?

¿Hay un método más eficiente para lograr este resultado?


Podría manejar las actualizaciones en una sola transacción, lo que podría mejorar significativamente el rendimiento. Use una función separada, decorada con @ transaction.commit_manually.

@transaction.commit_manually def update_latest_entries(latest_entry_list): for entry in latest_entry_list: entry.views += 1 entry.save() transaction.commit()


Si realmente necesita la eficiencia, en este momento debería bajar a SQL y ejecutar la actualización usted mismo. Sin embargo, eso no vale la complejidad añadida en este caso.

Con Django 1.1, podrá hacer esto en una sola llamada SQL a través del ORM utilizando los objetos F () para hacer referencia a los campos en el valor de la actualización.


Una mejora en el rendimiento de la entrada anterior. Esto da como resultado un hit de base de datos, con una subconsulta.

latest_entry_query_set = Entry.objects.filter(is_published=True) .order_by(''-date_published'')[:10] non_sliced_query_set = Entry.objects.filter(pk__in=latest_entry_query_set.values(''id'')) n = non_sliced_query_set.update(views=F(''views'')+1) print n or 0, ''items updated''


Puedes usar objetos F() para esto.

Aquí se muestra cómo importa F : from django.db.models import F

Nuevo en Django 1.1 .
Las llamadas a actualizar también pueden usar objetos F () para actualizar un campo en función del valor de otro campo en el modelo. Esto es especialmente útil para incrementar los contadores en función de su valor actual.

Entry.objects.filter(is_published=True).update(views=F(''views'')+1)

Aunque no puede hacer una actualización en un conjunto de consultas divididas ... edite: en realidad puede ...

Esto se puede hacer completamente en django ORM. Necesitas dos consultas SQL:

  1. Haz tu filtro y recoge una lista de claves primarias
  2. Realice una actualización en un conjunto de elementos de consulta no divididos que coincida con cualquiera de esas claves principales.

Obtener el conjunto de consultas no cortadas es la parte más difícil. Me pregunté sobre el uso de in_bulk pero eso devuelve un diccionario, no un conjunto de consultas. Uno usualmente usaría Q objects para hacer consultas complejas de tipo O y eso funcionaría, pero pk__in hace el trabajo mucho más simple.

latest_entry_ids = Entry.objects.filter(is_published=True)/ .order_by(''-date_published'') .values_list(''id'', flat=True)[:10] non_sliced_query_set = Entry.objects.filter(pk__in=latest_entry_ids) n = non_sliced_query_set.update(views=F(''views'')+1) print n or 0, ''items updated''

Debido a la forma en que django ejecuta las consultas de forma perezosa, esto da como resultado solo 2 visitas a la base de datos, sin importar cuántos elementos se actualicen.