【问题标题】:Optimising API queries using JSONField()使用 JSONField() 优化 API 查询
【发布时间】:2019-08-16 10:23:07
【问题描述】:

初始打开:我正在使用 postgresql JSONFields。

我的User 模型中有以下attribute(字段):

class User(AbstractUser):
   ...
   benefits = JSONField(default=dict())
   ...

我目前基本上使用 DRF 为前端的每个用户序列化收益:

    benefits = UserBenefit.objects.filter(user=self)
    serializer = UserBenefitSerializer(benefits, many=True)

由于底层返回的好处变化很小而且很慢,所以我考虑每次发生变化时都将JSON“缓存”在数据库中以提高UserBenefit.objects.filter(user=user)QuerySet的性能。相反,成为user.benefits 并有望减轻超过 10 万用户的数据库负载。


第一个问题:

我应该这样做吗?

第二问:

有没有一种有效的方法将对应的serializer.data<class 'rest_framework.utils.serializer_helpers.ReturnList'>写入JSON字段?

我目前正在使用:

data = serializers.serialize("json", UserBenefit.objects.filter(user=self))

【问题讨论】:

  • 通过添加此字段,您基本上消除了查询、后端逻辑和 json 序列化。 Json 序列化几乎总是很快,因此如果您预计当前方法会出现问题,您需要检查您的 SQL 查询(注意索引、FK、反向 FK、M2M、二进制字段和大型文本字段)和后端逻辑。每个用户有多少 UserBenefit 对象?
  • 所以我目前的问题是 DB 层可能随时受到 4/5 API 请求的影响,并且由于某种原因,UserBenefits ViewSet 对其余部分的运行速度相当缓慢。最终,很多查询都会以这种方式存储……
  • 如果不知道实际查询、它们的时间(最好使用EXPLAIN ANALYZE)和实际的后端逻辑(是否有任何可计算的字段正在发出其他数据库查询?),很难说什么是正确的方法?
  • 好的,如果我们暂时跳过它,如果我知道如何处理第二个问题,我可以测试我的假设。我目前在 JSON 中看到很多乱码 \stuff\ API返回...我需要以某种方式将benefits转换为json ...
  • 只要使用UserBenefitSerializer(benefits, many=True).data

标签: django django-rest-framework django-2.2 django-jsonfield


【解决方案1】:

第一个问题:

如果您不想使用缓存替代方案,这不是一个坏主意。

如果您因为某些更改或...而必须查询数据库,并且您无法缓存空洞请求,那么保存 JSON 对象的想法可能是一个不错的主意。这样,您只需检索数据并跳过序列化的大部分部分,还无需查询数据透视表以获取 m2m 数据。但也请注意,这样,您将向行中添加一大堆额外数据,除非您大部分时间都需要它们,否则您将获得您并不真正需要的额外数据,您可以提供帮助它在查询集上使用values 函数,但仍然需要更多编码。基本上,您将为第一次查询使用更多带宽,并使用更多存储空间来存储数据,而不是处理能力。此外,如果您在某些时候需要,在您的benefits 上实现分页将非常困难。

获取 m2m 关系数据的速度通常非常快,具体取决于数据库中的数据量,但获得更好性能的最终方法是缓存请求并尽可能减少数据库命中。

正如您可能经常听到的那样,您应该进行测试和基准测试,看看哪些选项最适合您,具体取决于您的要求和限制。在不了解整个范围和当前解决方案的信息的情况下,很难提出优化方法。

关于你的第二个问题:

我想我真的不明白。如果您要存储一个 JSON 对象,它是 User 模型中的一个字段,那么为什么需要 data = serializers.serialize("json", UserBenefit.objects.filter(user=self))

您不需要它,因为序列化程序可以只返回 JSON 字段数据。

【讨论】:

  • 为了回答您关于我为什么使用序列化程序的问题,我使用它来将数据写入 JSONField ...理想情况下,我想知道如何将 QuerySet 写入 JSONField.. .
  • 哦,好的,我现在明白了。您可以为您的利益模型编写一个 DRF 模型序列化程序,然后使用它来获取序列化数据然后存储它。
  • 嗯,我明白了:Object of type UUID is not JSON serializable
  • 如果有帮助,我尝试存储的 serializer.data 是 OrderedDict...
  • @WindUpLordVexxos 内置 json 模块不知道如何序列化 uuid。您可以使用 drf 中的JSONEncoder 来解决此错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 2012-12-05
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多