mysql - 如何进行利用 MySQL 后期行查找的 ORM 查询?

标签 mysql django django-models django-orm database-performance

在我的 Django 应用程序中,我定义了一个模型,如下所示:

class NamedContainer(models.Model):
    name = models.CharField(max_length=50)
    capacity_ml = models.PositiveIntegerField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['name', 'capacity_ml']

随着时间的推移,该表已经变得足够大,开始导致一些查询性能问题,特别是在依赖限制/偏移量进行切片时。其他切片方法在设计上可能具有更好的性能,但不幸的是,现在我仍然坚持限制/偏移。

然而,MySQL has a technique called "late row lookups"这对我的问题有很大帮助,简而言之,使用这种技术的原始 MySQL 查询看起来像

SELECT t2.* FROM (
    SELECT *
    FROM `core_namedcontainer`
    WHERE `updated_at` >= '2019-01-01 05:00:00.000Z'
    ORDER BY id ASC
    LIMIT 500 OFFSET 10000
) AS t1
JOIN `core_namedcontainer` AS t2
ON t1.id = t2.id
ORDER BY `name` ASC, `capacity_ml` ASC

我只设法破坏了 ORM 查询以生成如下查询

SELECT *
FROM `core_namedcontainer`
WHERE (
  `core_namedcontainer`.`id` IN (
      SELECT U0.`id`
      FROM `core_namedcontainer` U0
      WHERE (
        U0.`updated_at` >= 2019-01-01 05:00:00
      )
      ORDER BY U0.`name` ASC, U0.`capacity_ml` ASC
      LIMIT 500 OFFSET 10000
    )
)
ORDER BY `core_namedcontainer`.`name` ASC, `core_namedcontainer`.`capacity_mL` ASC

它只是使用子查询而不是自身的连接,并且在评估查询时,MySQL 会提示

NotSupportedError: (1235, "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'")

django 应用程序使用的是 MySQL 5.6,由于各种原因,它需要很长时间才能升级到任何更新的版本。

我知道我可以按照我需要的方式发出原始 SQL 查询,但我希望有一种方法可以将此技术转换为 Django ORM 语法,以便我可以在我的模型上利用此技术作为基础查询集:

class NamedContainerManager(models.Manager):
    def get_queryset(self):
        queryset = super().get_queryset()
        # do some ORM magic here to implement mysql late row lookup in all queries
        return queryset

class NamedContainer(models.Model):
    ...
    objects = NamedContainerManager()

非常感谢所有帮助!

最佳答案

OFFSET 会导致跳过或重复行。当心。

OFFSET 是 O(N*N)。这是因为它必须跨过所有“偏移”行。

更好的解决方案是“记住您离开的地方”而不是使用 OFFSET。参见 http://mysql.rjweb.org/doc.php/pagination

你说“现在我被限制/偏移所困”。我不接受。在 ORM 中应该可以重新制定以记住您离开的地方。

关于mysql - 如何进行利用 MySQL 后期行查找的 ORM 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58003070/

相关文章:

php - 使用 php 查询选择所有订单

python - 如何在 Django Photologue 中制作自定义照片效果?

Django:如何从 ManyToMany 迁移到 ForeignKey?

python - 在模型 save() 中如何获取以 'foo' 开头的所有字段

mysql - MySQL数据库大量记录更新

php - 尝试更新小时表中的 time_out 时出现语法错误

python - 通过 pip 安装 mysqlclient 时遇到问题

python - Django 小数精度损失

python - 如果没有找到 Object.get() 抛出异常

python - 如何在 Django 管理更改表单中显示相关表的内容?