Django ORM 对 QuerySet 的迭代真的很慢

Django ORM really slow iterating over QuerySet

我正在做一个新项目,必须非常快速地构建几页的大纲。

我导入了一个包含 280,000 个产品的目录,我想进行搜索。我选择了 Whoosh 和 Haystack 来提供搜索,因为我在之前的项目中使用过它们。 我为索引添加了定义并启动了该过程。然而,Django 似乎真的非常非常真的 遍历 QuerySet 很慢。 最初,我认为索引编制花费了超过 24 小时——这看起来很荒谬,所以我测试了一些其他的东西。我现在可以确认迭代 QuerySet 需要很多小时。

也许在 Django 2.2 中有一些我不习惯的地方?我以前使用的是 1.11,但我想我现在使用的是更新的版本。

我要迭代的模型:

class SupplierSkus(models.Model):
    sku = models.CharField(max_length=20)
    link = models.CharField(max_length=4096)
    price = models.FloatField()
    last_updated = models.DateTimeField("Date Updated", null=True, auto_now=True)
    status = models.ForeignKey(Status, on_delete=models.PROTECT, default=1)
    category = models.CharField(max_length=1024)
    family = models.CharField(max_length=20)
    family_desc = models.TextField(null=True)
    family_name = models.CharField(max_length=250)
    product_name = models.CharField(max_length=250)
    was_price = models.FloatField(null=True)
    vat_rate = models.FloatField(null=True)
    lead_from = models.IntegerField(null=True)
    lead_to = models.IntegerField(null=True)
    deliv_cost = models.FloatField(null=True)
    prod_desc = models.TextField(null=True)
    attributes = models.TextField(null=True)
    brand = models.TextField(null=True)
    mpn = models.CharField(max_length=50, null=True)
    ean = models.CharField(max_length=15, null=True)
    supplier = models.ForeignKey(Suppliers, on_delete=models.PROTECT)

而且,正如我提到的,table.

中大约有 280k 行

当我做一些简单的事情时:

from products.models import SupplierSkus
sku_list = SupplierSkus.objects.all()
len(sku_list)

该进程将很快耗尽大部分 CPU 电量并且不会完成。同样,我不能迭代它:

for i in sku_list:
    print(i.sku)

也只需要几个小时而不打印一行。但是,我可以使用以下方法对其进行迭代:

for i in sku_list.iterator():
    print(i.sku)

这对我帮助不大,因为我仍然需要通过 Haystack 进行索引,我相信这些问题是相关的。

我以前参与的一些项目并非如此。即使是更大的列表(3-5m 行)也会很快迭代。查询列表长度需要一些时间,但 return 结果以秒而不是小时为单位。

所以,我想知道,这是怎么回事? 这是其他人遇到的事情吗?

好的,我发现问题出在 Python MySQL 驱动程序上。如果不使用 .iterator() 方法,for 循环将卡在 QuerySet 的最后一个元素上。我已经在 上发布了更详细的答案。

I was not using the Django recommended mysqlclient. I was using the one created by Oracle/MySQL. There seems to be a bug that causes an iterator to get "stuck" on the last element of the QuerySet in a for loop and be trapped in an endless loop in certain circumstances.

仔细想想,这很可能是MySQL驱动的一个设计特点。我记得以前使用此驱动程序的 Java 版本时遇到过类似的问题。也许我应该放弃 MySQL 并转向 PostgreSQL?

无论如何我都会尝试用 Oracle 提出错误。