Django ManyToManyField场景下如何高效获取每台设备对应的group_id
你之前遍历拉取关联字段耗时过长的核心原因是触发了N+1查询问题:每遍历一台设备就单独发起一次数据库请求拉取关联分组,10万台设备就会产生10万+次数据库请求,效率自然极低。以下是两种高效解决方案:
方案1:ORM预加载(兼容ORM操作习惯)
用Django ORM自带的prefetch_related预加载反向关联的分组数据,全程仅需2次数据库查询,符合Django开发规范:
# 预加载所有设备关联的分组数据 devices = Devices.objects.prefetch_related("groups_set").all() # 遍历获取每台设备的group_id列表,不会产生额外数据库请求 for device in devices: group_ids = [group.group_id for group in device.groups_set.all()] # 后续业务逻辑处理group_ids
注:如果你的
ManyToManyField定义了related_name参数,把上述代码中的groups_set替换为你自定义的关联名即可。
方案2:直接查询多对多中间表聚合(性能最优,适合纯ID映射场景)
多对多关联的中间表存储了所有设备和分组的id对应关系,直接查询中间表仅需1次数据库请求,不需要实例化ORM模型对象,内存占用和查询速度都是最优的,尤其适合10万级以上的大数据量场景:
from collections import defaultdict # 获取Django自动生成的多对多中间表模型 GroupDeviceThrough = Groups.devices.through # 一次性查询所有设备和分组的id对应关系 relations = GroupDeviceThrough.objects.values_list("devices_id", "group_id") # 聚合为{设备id: [所属分组id列表]}的映射字典 device_group_map = defaultdict(list) for dev_id, grp_id in relations: device_group_map[dev_id].append(grp_id)
优化提示
- 如果需要包含无分组的设备,只需额外查询一次所有设备id,把不存在于
device_group_map的设备id对应值设为空列表即可 - 若数据量过大担心内存溢出,可以给
values_list加上.iterator()方法流式读取关联数据,内存占用可控制在KB级
内容的提问来源于stack exchange,提问作者Smruti Sahoo
相关产品推荐
相关产品推荐

