查询2198条数据耗时近6分钟,如何优化Django API查询速度?
优化Django Product表查询速度的方案
首先明确问题核心:当前代码触发了N+1查询——主查询拉取所有Product后,序列化时每个Product都要单独查询一次Brand表,直接导致2000+次SQL请求,这是耗时的根本原因。以下是具体优化方案:
1. 预取关联外键数据(解决N+1查询)
用select_related一次性连表查询Product和关联的Brand数据,把原本2000+次SQL请求合并为1次:
@api_view(['GET']) def autofill_api(request): # 用select_related预取brand关联数据 items = Product.objects.all().select_related('brand') serializer = AutoFillSerializer(items, many=True) return Response(serializer.data)
注意:select_related适用于ForeignKey/OneToOneField这类多对一/一对一关联;如果涉及ManyToManyField关联,需改用prefetch_related。
2. 避免序列化所有字段
当前fields = __all__会返回Product表的所有字段,若存在大量前端不需要的字段(如创建时间、内部状态字段),会增加数据传输和序列化耗时。明确指定需要的字段:
class AutoFillSerializer(serializers.ModelSerializer): brand_name = serializers.CharField(source='brand.brand') class Meta: model = Product # 只列出前端需要的字段,示例: fields = ['id', 'product_name', 'price', 'brand_name']
3. 分页返回数据
如果Product表数据量较大(2000条左右),一次性返回所有数据会导致响应包过大、前端加载慢。用Django REST Framework的分页器拆分数据:
from rest_framework.pagination import PageNumberPagination class ProductPagination(PageNumberPagination): page_size = 100 # 每页返回100条数据 page_size_query_param = 'page_size' max_page_size = 500 @api_view(['GET']) def autofill_api(request): items = Product.objects.all().select_related('brand') # 应用分页 paginator = ProductPagination() paginated_items = paginator.paginate_queryset(items, request) serializer = AutoFillSerializer(paginated_items, many=True) return paginator.get_paginated_response(serializer.data)
前端可通过?page=1、?page=2分页获取数据,大幅降低单次请求的耗时。
4. 直接查询所需字段(跳过模型实例序列化)
如果不需要完整的Product模型实例,用values直接查询结构化数据,减少模型实例创建和序列化的开销:
from django.db.models import F @api_view(['GET']) def autofill_api(request): # 直接查询需要的字段,包括关联的brand名称 items = Product.objects.all().select_related('brand').values( 'id', 'product_name', 'price', brand_name=F('brand__brand') ) return Response(list(items))
这种方式无需Serializer,响应速度更快,适合只需要基础数据的场景。
5. 数据库层面优化
- 确保外键字段
brand_id有索引:Django默认会给ForeignKey字段创建索引,若之前手动删除过,需重新添加; - 若数据量达十万级以上,给常用查询字段(如
product_name、brand_id)添加联合索引,进一步提升查询效率。
6. 缓存策略优化(兼顾实时性)
若使用cache_page,可通过以下方式平衡缓存命中率和实时性:
- 设置较短的缓存过期时间(如5分钟);
- 用Django信号监听Product或Brand的更新/删除事件,自动清除对应缓存,确保用户能及时看到最新数据:
from django.core.cache import cache from django.db.models.signals import post_save, post_delete from django.dispatch import receiver @receiver(post_save, sender=Product) @receiver(post_delete, sender=Product) @receiver(post_save, sender=Brand) @receiver(post_delete, sender=Brand) def clear_autofill_cache(sender, **kwargs): # 删除autofill_api的缓存 cache.delete_pattern('views.decorators.cache.cache_page.*autofill_api*')
内容的提问来源于stack exchange,提问作者Hector Devough
相关产品推荐
相关产品推荐

