如何优化含外键与多对多字段的模型查询?
优化Django多对多图片关联的查询性能
当前获取产品列表数据时,总共要执行14次查询,其中大部分查询都用于拉取每个产品对应的关联图片(Image是多对多字段,单个产品对应多张图片)。
原实现代码:
productList = Variants.objects.select_related('prod_id__category') for productName in productList: products = dict() prod_id = productName.id products['id'] = prod_id products['category'] = productName.prod_id.category.category_name products['prod_name'] = productName.prod_id.prod_name prod_images = list(productName.image.values_list('image_url').distinct()) image_list = list() for image in prod_images: image_list.append(image[0]) products['image'] = image_list price = productName.price products['price'] = price createdAt = productName.createdAt products['createdAt'] = createdAt productListDict.append(products)
优化方案
使用Django的prefetch_related预加载多对多关联的Image数据,彻底解决循环中的N+1查询问题,大幅减少查询次数:
from django.db.models import Prefetch # 预加载关联的图片数据,只取需要的image_url字段并去重 productList = Variants.objects.select_related('prod_id__category').prefetch_related( Prefetch( 'image', queryset=Image.objects.values_list('image_url').distinct(), to_attr='prefetched_images' ) ) productListDict = [] for product in productList: product_dict = { 'id': product.id, 'category': product.prod_id.category.category_name, 'prod_name': product.prod_id.prod_name, # 直接从预加载的属性中提取图片URL,无需额外查询 'image': [img[0] for img in product.prefetched_images], 'price': product.price, 'createdAt': product.createdAt } productListDict.append(product_dict)
优化说明
select_related用于预加载外键关联的prod_id和category数据,避免外键字段的额外查询prefetch_related搭配Prefetch对象,一次性拉取所有产品对应的图片数据,并且只查询需要的image_url字段同时去重,减少数据传输量- 循环中直接使用预加载的
prefetched_images属性,无需再执行任何数据库查询,总查询次数可从14次降至2次左右
内容的提问来源于stack exchange,提问作者sash
相关产品推荐
相关产品推荐

