【问题标题】:Reducing database operation time Django/ Mysql减少数据库操作时间 Django/Mysql
【发布时间】:2016-09-14 22:09:20
【问题描述】:

所以,问题是我有一个相当大的电子邮件列表 ~ 250,000 个条目。

我有另一个包含无效电子邮件列表的表格 ~ 50,000 我需要从第一个表格中删除(标记为非活动)。为此,我运行了一个简单的 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 代码或其他方式。

救命!

【问题讨论】:

    标签: python mysql django database


    【解决方案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 个查询而不是 1 个,并将 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)'
    

    【讨论】:

    • 没错,Raw SQL 要快得多。
    【解决方案2】:

    您可能想看看一些优化。尝试获取值列表,而不是遍历每个对象的 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'])

    这只会更新布尔字段。 https://docs.djangoproject.com/en/1.10/ref/models/instances/#updating-attributes-based-on-existing-fields

    如果可能的话,还可以尝试通过 id 或字符串以外的其他字段来 .get() 对象。

    【讨论】:

      【解决方案3】:

      经过几次迭代,我使用了这个功能,速度超过了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 个对象保存在内存中的查询集中。以及来自内存中无效列表的电子邮件列表。

      然后我只有在找到匹配的电子邮件时才需要访问数据库,以便将其保存为非活动状态。

      【讨论】:

        猜你喜欢
        • 2015-06-22
        • 2023-03-08
        • 2016-02-07
        • 2016-07-10
        • 1970-01-01
        • 1970-01-01
        • 2017-04-19
        • 2011-09-24
        • 1970-01-01
        相关资源
        最近更新 更多