How to optimize a batch query to make it faster

Viewed 30

When changing the status of a document, I would like to put all the products in the document into stock. This involves changing several fields. At low amount of product instances, the query works quickly >50ms. However, some documents have products in quantities of, for example, 3000. Such a query takes more than a second. I know that there will be cases with much higher number of instances. I would like the query to be faster.

A simple loop takes ~1sec.

class PZ_U_Serializer(serializers.ModelSerializer):
    class Meta:
        model = PZ
        fields = '__all__'

    def update(self, instance, validated_data):
        items = instance.pzitem_set.all()
        bulk_update_list = []
        for item in items:
            item.quantity = 100
            item.quantity_available_for_sale = 100
            item.price = 100
            item.available_for_sale = True
            item.save()
        return super().update(instance, validated_data)

Batch_update takes about 400ms per field. In this case 1600ms (which is slower than a loop).

class PZ_U_Serializer(serializers.ModelSerializer):
    class Meta:
        model = PZ
        fields = '__all__'

    def update(self, instance, validated_data):
        items = instance.pzitem_set.all()
        bulk_update_list = []
        for item in items:
            item.quantity = 100
            item.quantity_available_for_sale = 100
            item.price = 100
            item.available_for_sale = True
            bulk_update_list.append(item)
        items.bulk_update(bulk_update_list, ['quantity', 'price', 'quantity_available_for_sale', 'available_for_sale'], batch_size=1000)
        return super().update(instance, validated_data)

In post-gre console I see at (3000 objects) about 11,000 read hits. I tried adding transaction.atomic before the loop, but it didn't change anything (if I did it right).

1 Answers

Did you try to use queryset's update() method?
It should save you lots of update requests & loop executions :

    def update(self, instance, validated_data):
        instance.pzitem_set.all().update(
            quantity = 100, 
            quantity_available_for_sale = 100,
            price = 100,
            available_for_sale = True,
        )
        return super().update(instance, validated_data)

More infos on the official doc here.

Related