장고 효율성 - select_related
Empecemos con un problema sencillo, supongamos que tenemos un modelo de subforo de un foro, en donde cada sufbforo puede tener un comentario, y ese comentario a su vez puede pertenecer a un subforo en concreto.
class SubForo(models.Model):
name = models.CharField(max_length=255, null=True)
creator = models.CharField(max_length=255, null=True)
hashtags = models.CharField(max_length=255, null=True)
class Comentario(models.Model):
comment = models.TextField()
subforo = models.ForeignKey(SubForo, on_delete=models.CASCADE)
Ahora para poder listar todos los comentarios con el foro al que pertenece, lo más común es encontrar código como este:
@api_view(["GET"])
@permission_classes([permissions.IsAuthenticated])
def obtener_comentarios_foro(request):
comentarios = Comentario.objects.all()
comentarios_con_foro = {}
for comentario in comentarios:
comentarios_con_foro['comentario'] = comentario.comment
comentarios_con_foro['foro'] = comentario.subforo.name
print(comentarios_con_foro)
El problema de esto es que estamos accediendo a la base de datos por lo menos, dos veces:
es decir que si tengo 10 comentarios, iríamos a buscar todos los comentarios y además hacer una query para ir a buscar el subforo al que pertenece ese comentario, la querie seria algo como esto:
SELECT
`comentario`.`id`,
`comentario`.`comment`,
`comentario`.`subforo_id`
FROM
`comentario`;
#QUERIES A EJECUTAR UNA VEZ QUE OBTENEMOS EL COMENTARIO CON SU SUBFORO_ID CORRESPONDIENTE:
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 1 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 1 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 1 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 2 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 2 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 3 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 4 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 4 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 4 LIMIT 21;
SELECT `subforo`.`id`, `subforo`.`name`, `subforo`.`creator`, `subforo`.`hashtags` FROM `subforo` WHERE `subforo`.`id` = 5 LIMIT 21;
Quizás en un proyecto chico esto no sea un gran problema, pero ahora Imaginemos que tenemos 600 comentarios en el subforo… Sería totalmente ineficiente hacer un select por cada uno de esos comentarios.
¿해결책? Usar select_related, de esta forma vamos a hacer una query mucho más larga pero el tiempo de respuesta será mucho menor:
@api_view(["GET"])
@permission_classes([permissions.IsAuthenticated])
def obtener_comentarios_foro(request):
comentarios = Comentario.objects.select_related('subforo').all()
comentarios_con_foro = {}
for comentario in comentarios:
comentarios_con_foro['comentario'] = comentario.comment
comentarios_con_foro['foro'] = comentario.subforo.name
print(comentarios_con_foro)
la query nos quedaría de esta manera:
SELECT
"comentario"."id",
"comentario"."comment",
"comentario"."subforo_id",
"subforo"."id",
"subforo"."name",
"subforo"."creator",
"subforo"."hashtags",
FROM
"comentario"
INNER JOIN "subforo" ON (
"comentario"."subforo_id" = "subforo"."id"
)
Demostraciones de un proyecto con datos reales
select_related API를 사용하여 응답하는 방법:
select_related api sin utilizar 응답에 대한 질문:
Reference
이 문제에 관하여(장고 효율성 - select_related), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/nahuelsegovia/django-eficiente-selectrelated-405m텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)