【问题标题】:Django filtering large dataset taking too longDjango过滤大型数据集花费太长时间
【发布时间】:2023-04-04 10:45:01
【问题描述】:

我知道有很多关于这个主题的问题,但我找不到我的任何案例。我的问题很简单。

在我的 influencer 应用程序中,我有 Note 模型,其中包含大约 30 个字段:

class Note(models.Model):
    desc = models.TextField()
    likeCount = models.PositiveIntegerField()
    commentCount = models.PositiveIntegerField()
    ...
    tags = models.ManyToManyField(Tag)
    postTs = models.DateTimeField(null=True)

AWS RDS 托管的我的 PostgreSQL 数据库中有超过 100 万 Notes。

现在当我执行以下代码时:

notes = (
    Note.objects.filter(desc__icontains='some word')
                .values("likeCount", "collectCount", "shareCount", "commentCount", "postTs")[:10]
)
print(len(notes))  # Output: 10

大约需要 7 秒

生成的 SQL 查询是:

SELECT "influencer_note"."likeCount",
       "influencer_note"."collectCount",
       "influencer_note"."shareCount",
       "influencer_note"."commentCount",
       "influencer_note"."postTs"
  FROM "influencer_note"
 WHERE UPPER("influencer_note"."desc"::text) LIKE UPPER('%some word%')
 LIMIT 10

我想我已经做了很多事情来优化查询(例如选择唯一必要的字段并限制数据的数量——10 显然是一个小数字),但它仍然需要时间异常。

此问题的可能原因是什么,我该如何进一步优化?

最终,我需要使用过滤后的查询集制作图表,这就是为什么我需要分页或LIMIT以外的解决方案。

提前谢谢你。

【问题讨论】:

  • 你在那个专栏上创建了index,它不应该那么慢..

标签: python django postgresql


【解决方案1】:

这里的icontains (LIKE UPPER) 很可能是一项耗费大部分查询评估时间的昂贵操作。 不确定您是否可以使用 Django ORM 进行更多优化,但也许您可以使用 PostgreSQL 矢量搜索尝试full text search 的一些方法。

另一种选择是使用更合适的工具,例如 ElasticSearch。你可以阅读一些入门指南here

【讨论】:

  • 感谢您的评论,但恐怕icontains 并不是唯一需要花费大量时间的人。在更小的CharField 上使用contains 需要相似的时间。我会研究你的其他建议,让你知道什么对我有用。
  • 即使Note.objects.all().count() 也需要大约 150 秒。这是预期的吗?
  • @shinhong 是的,这是意料之中的,因为在后台 Django 将运行简单的查询 SELECT COUNT(*) FROM table_name 执行 full table scan。在 (i)contains 的两种情况下,您的查询将逐行比较所有表,以将 desc 与您的值进行比较,这很慢。
【解决方案2】:

您显示的查询可以通过索引加速:

create extension pg_trgm;
create index on influencer_note using gin (UPPER("desc"::text) gin_trgm_ops)

虽然 Django 为什么在此处的查询中注入 UPPER 调用,而不是仅仅使用 ILIKE 做明智的事情,但对我来说还是个谜。

【讨论】:

  • 不幸的是,我的 desc 字段包含太多字节,会引发“索引行需要 8592 字节,最大大小为 8191”错误。
  • 这不是 gin_trgm_ops 索引会抛出的错误。
  • 你是对的。我错过了gin_trgm 部分。据我了解,为了使用 GIN 索引,该列必须是 tsvector。但是tsvector 支持像中文这样的非英文字符吗?创建触发器时,我似乎需要提供语言配置,例如pg_catalog.english,但我希望它不仅能够搜索英文而且能够搜索中文(或 unicode)。我的选择是什么?如果这个问题没有意义,请原谅。我是 SQL 新手。
  • 我执行您发布的命令已经超过 24 小时。它仍在运行,我想知道我需要等待多长时间。我的数据库实例具有最便宜的配置:t2.micro、1 个 vCPU、1GB 的 RAM。你能粗略估计一下这件事会持续多久吗?
猜你喜欢
  • 2017-11-17
  • 2019-02-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多