﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
36858	Optimize `db_default` creation	Adam Johnson	Adam Johnson	"Currently, `Field._get_default()` returns a `lambda` that instantiates a new `DatabaseDefault` each time it is called. This expression is identical each time, so this work is wasted. We can optimize it by creating a single expression that is returned each time.

Thanks to Adam Sołtysik for the hint in https://forum.djangoproject.com/t/faster-bulk-create-using-dictionaries/43891

Benchmarked with a quick modification to the test suite:

{{{#!diff
diff --git ./tests/bulk_create/tests.py ./tests/bulk_create/tests.py
index 397fcb9186..ddfe315c0c 100644
--- ./tests/bulk_create/tests.py
+++ ./tests/bulk_create/tests.py
@@ -877,6 +877,16 @@ def test_db_default_field_excluded(self):
             2 if connection.features.can_return_rows_from_bulk_insert else 1,
         )
 
+
+    def test_benchmark(self):
+        import time
+        start = time.perf_counter()
+        DbDefaultModel.objects.bulk_create(
+            [DbDefaultModel(name=f""obj {i}"") for i in range(100_000)]
+        )
+        end = time.perf_counter()
+        print(f""{end - start:.3f} seconds"")
+
     @skipUnlessDBFeature(
         ""can_return_rows_from_bulk_insert"", ""supports_expression_defaults""
     )
}}}

Run with:

{{{
./runtests.py --parallel 1 bulk_create.tests.BulkCreateTests.test_benchmark -v 0
System check identified no issues (0 silenced).
0.617 seconds
----------------------------------------------------------------------
Ran 1 test in 0.618s

OK
}}}

Results, best of 3:

Before: 0.691 seconds
After: 0.610 seconds

A ~12% speedup on this `bulk_create()` operation, on a model with a single `db_default` field."	Cleanup/optimization	closed	Database layer (models, ORM)	dev	Normal	fixed			Ready for checkin	1	0	0	0	0	0
