【问题标题】:Efficiently Saving 60K Records in database with django rest frame work使用 django rest 框架有效地在数据库中保存 60K 记录
【发布时间】:2020-10-30 20:15:37
【问题描述】:

我有一个端点(例如 http://localhost:8000/api/create/),它使用 django rest 框架在 mysql db 中创建新记录

views.py

class CreateItem(viewsets.ModelViewSet):
  .
  .
  .
  def perform_create(self, serializer):
    if serializer.is_valid():
      serializer.save()

serializers.py

class CreateItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = '__all__'

现在我有一个要求,60K 个人 HTTP 请求将在脚本的帮助下在短时间内在此端点发出

我怎样才能最有效地处理它,这将花费更少的时间和资源。

我读到了 Django atomic and celery task,但完全不知道如何利用它来满足这个要求。

任何帮助将不胜感激

提前致谢

【问题讨论】:

    标签: python mysql django django-rest-framework celery


    【解决方案1】:

    因此,最简单的方法是将代码包装在原子事务中。

    from django.db import transaction
    
    with transaction.atomic():
        serializer.create() # This code goes where you are calling the serializer.create() function, NOT inside the serializer itself else it's useless
    

    它的作用是缓冲所有插入,然后一次性执行。

    bulk_create 甚至更快,但你不能用序列化器来做到这一点。

    【讨论】:

    • 所以如果我这样做if serializer.is_valid(): with transaction.atomic(): serializer.save() 这将有我的要求?
    • 没有。使用 transaction.atomic() 的重点是将多个插入组合在一起。如果您基于每个对象执行此操作,则它是无用的。您需要从代码中所有序列化程序正在处理的更高点开始。
    • 我在这个视图的 serializer.py 文件中只有一个模型序列化器。如果我做@transaction.atomic decorator in def perform_create 怎么办?这就是你所说的更高点吗?
    • @young_minds1 否您的代码中必须有一个 for 循环,该循环遍历您一个一个序列化的所有 60k+ 个实例。 with transaction.atomic() 应该在 for 循环之前。这样所有的序列化和它们的 save() 都发生在 transaction.atomic() 的单个执行中
    • 但我会从该端点上的每个 HTTP 发布请求中获取数据,这会在很短的时间内发出 60K POST 请求,因为它将由脚本执行。我将如何在它上面运行 for 循环?因为我在单个 HTTP 请求中获取数据
    【解决方案2】:

    如果您想通过 HTTP 请求传递数据来创建对象,Celery 不会这样做,因为您需要先将其发送到 Django。

    但是,您可以通过在同一个请求上创建多个对象来提高性能:

    您可以创建一个操作bulk_create 并创建一个只有一个字段的BulkSerializerobjects = MySerializer(many=True)

    然后尝试类似的方法:

    class CreateItem(viewsets.ModelViewSet):
      .
      .
      .
      @action(methods=["post"], detail=False)
      def bulk_create(self, request):
        serialized = BulkSerializer(data=request.data)
        serialized.is_valid(raise_exception=True)
        for validated_data in serialized.validated_data["objects"]:
          # Create object here
        return Response({"status": "ok"})
    

    (您可以通过重用与 create 中相同的逻辑来改进这一点,使用一些 try / except 来处理失败,并使用 MULTISTATUS 进行响应,但这是要点)

    这样,您可以创建模型,比如 100 x 100 或 1000 x 1000。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多