Fixed #35936 -- Used unnest for bulk inserts on Postgres when possible.

This should make bulk_create significantly faster on Postgres when provided
only literal values.

Thanks James Sewell for writing about this technique, Tom Forbes for
validating the performance benefits, David Sanders and Mariusz Felisiak
for the review.
This commit is contained in:
Simon Charette 2024-11-17 00:30:00 -05:00 committed by Sarah Boyce
parent 2638b75554
commit a16eedcf9c
3 changed files with 86 additions and 0 deletions

View file

@ -0,0 +1,29 @@
import unittest
from django.db import connection
from django.db.models.expressions import RawSQL
from django.test import TestCase
from ..models import Square
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL tests")
class BulkCreateUnnestTests(TestCase):
def test_single_object(self):
with self.assertNumQueries(1) as ctx:
Square.objects.bulk_create([Square(root=2, square=4)])
self.assertNotIn("UNNEST", ctx[0]["sql"])
def test_non_literal(self):
with self.assertNumQueries(1) as ctx:
Square.objects.bulk_create(
[Square(root=2, square=RawSQL("%s", (4,))), Square(root=3, square=9)]
)
self.assertNotIn("UNNEST", ctx[0]["sql"])
def test_unnest_eligible(self):
with self.assertNumQueries(1) as ctx:
Square.objects.bulk_create(
[Square(root=2, square=4), Square(root=3, square=9)]
)
self.assertIn("UNNEST", ctx[0]["sql"])