En Django, select_related y prefetch_related están diseñados para detener la avalancha de consultas a la base de datos causada por el acceso a objetos relacionados. En este artículo, veremos cómo reduce la cantidad de consultas y hace que el programa sea mucho más rápido.
- select_related() «sigue» las relaciones de clave externa, seleccionando datos adicionales de objetos relacionados cuando ejecuta su consulta.
- prefetch_related() realiza una búsqueda separada para cada relación y realiza la «unión» en Python.
Uno usa select_related cuando el objeto que va a seleccionar es un solo objeto, por lo que OneToOneField o ForeignKey. Utiliza prefetch_related cuando va a obtener un «conjunto» de cosas, así que ManyToManyFields como indicó o invierte ForeignKeys. Solo para aclarar lo que quiero decir con «Reverse ForeignKeys».
Ejemplo para ilustrar el concepto de Prefetch_related y select_related –
La clasificación anterior puede no ser tan clara, veamos un ejemplo:
Python3
class ModelA(models.Model): pass class ModelB(models.Model): a = models.ForeignKey(ModelA, on_delete=models.CASCADE) # Forward ForeignKey relationship ModelB.objects.select_related('a').all() # Reverse ForeignKey relationship ModelA.objects.prefetch_related('modelb_set').all()
select_related obtiene todos los datos a la vez a través de consultas de asociación de combinación de varias tablas y mejora el rendimiento al reducir el número de consultas de la base de datos. Utiliza declaraciones JOIN de SQL para optimizar y mejorar el rendimiento al reducir la cantidad de consultas SQL. Este último es para resolver el problema en la consulta SQL a través de una instrucción JOIN. Sin embargo, para relaciones de muchos a muchos, no es aconsejable utilizar sentencias SQL para resolverlas, porque las tablas obtenidas por JOIN serán muy largas, lo que conducirá a un aumento en el tiempo de ejecución y la ocupación de memoria de las sentencias SQL. ¡La solución a prefetch_related() es consultar cada tabla por separado y luego usar Python para manejar su relación!
Aquí hay unos ejemplos :
Models.py dice lo siguiente:
Python3
from django.db import models class Province(models.Model): name = models.CharField(max_length = 10) def __unicode__(self): return self.name class City(models.Model): name = models.CharField(max_length = 5) province = models.ForeignKey(Province) def __unicode__(self): return self.name class Person(models.Model): firstname = models.CharField(max_length = 10) lastname = models.CharField(max_length = 10) visitation = models.ManyToManyField(City, related_name = "visitor") hometown = models.ForeignKey(City, related_name = "birth") living = models.ForeignKey(City, related_name = "citizen") def __unicode__(self): return self.firstname + self.lastname
select_related –
usamos la función select_related():
>>> citys = City.objects.select_related().all() >>> for c in citys: ... print c.province ...
Solo hay una consulta SQL, lo que obviamente reduce en gran medida la cantidad de consultas SQL:
SELECT `Optimize_city`.`id`, `Optimize_city`.`name`, `Optimize_city`.`province_id`, `Optimize_province`.`id`, `Optimize_province`.`name` FROM`Optimize_city` INNER JOIN `Optimize_province` ON (`Optimize_city`.`province_id`=`Optimize_province`.`id`);
prefetch_relacionado –
Aquí podemos ver que Django usa INNER JOIN. Me gustaría aclarar una cosa: Optimize es un nombre de nuestra aplicación. Si queremos obtener todos los nombres de las ciudades de Hubei, podemos hacer esto:
> HB=Province.objects.prefetch_related('city_set').get(name__iexact=u"Hubei Province") >>> for city in hb.city_set.all(): ... city.name ...
Consultas SQL activadas:
SELECT `Optimize_province`.`id`, `Optimize_province`.`name` FROM `Optimize_province` WHERE `Optimize_province', `name `LIKE'Hubei Province'; SELECT `Optimize_city`.`id`, `Optimize_city`.`name`, `Optimize_city`.`province_id` FROM `Optimize_city` WHERE `Optimize_city`.`province_id` IN (1);
Como podemos ver, la captación previa se implementa mediante la instrucción IN. De esta forma, cuando hay demasiados objetos en QuerySet, pueden surgir problemas de rendimiento dependiendo de las características de la base de datos.
Publicación traducida automáticamente
Artículo escrito por 05avinashvish y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA