所以,问题是我有一个中等大小的电子邮件列表~250,000个条目。
我有另一个表包含无效电子邮件列表~5000,我需要从第一个表中删除(标记为非活动状态)。为此,我运行了一个简单的django函数,每个循环需要3-4秒。代码是:
def clean_list():
id = 9
while id<40000:
i = Invalid.objects.get(id=id)
y = i.email.strip()
f = IndiList.objects.get(email__contains=y)
f.active = False
f.save()
id +=1
什么是更好的方法呢?无论是SQL查询还是更好的django代码或其他方式。
帮助!
答案 0 :(得分:1)
您可能需要了解一些优化措施。不要为每个对象循环获取get,而是尝试获取值列表:
queryset = Invalid.objects.filter(id__range=(9,40000))
queryset_list = queryset.values_list('email' flat=True)
https://docs.djangoproject.com/en/1.10/ref/models/querysets/#values-list
然后循环遍历值列表并在电子邮件上执行.get()。最后你也可以这样做:
f.active = False
f.save(update_fields=['active'])
如果可能,还尝试通过id或字符串之外的其他字段找到.get()对象的方法。
答案 1 :(得分:1)
未测试:
IndiList.objects.filter(email__in=Invalid.objects.only('email').all()).update(active=False)
我不确定Django是否足够聪明,可以从中构建子查询,如果没有,那么应该这样做:
IndiList.objects.filter(email__in=Invalid.objects.all().values_list('email', flat=True)).update(active=False)
第二种方法的问题是它将生成2个查询而不是一个,并将50,000个ID注入第二个sql查询字符串,所以我更愿意在这一点上使用原始sql:
from django.db import connection
cursor = connection.cursor()
cursor.execute = 'UPDATE indilist SET active=false WHERE email IN (SELECT email FROM invalid)'
答案 2 :(得分:0)
经过几次迭代后,我使用的功能超过 1000倍。
def clean_list3():
pp = Invalid.objects.filter(id__gte=9)
listd = [oo.email.strip() for oo in pp]
for e in IndiList.objects.all():
if e.email.strip() in listd:
e.active=False
e.save()
print(e.id)
技巧很简单,而不是每次都要点击数据库,我将250,000个对象保存在内存中的查询集中。以及内存中无效列表的电子邮件列表。
然后我不得不在我们找到匹配的电子邮件时才点击数据库,以便将其保存为非活动状态。