From 2638b75554d2624dca3062a8da113a47f855f2a2 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Sat, 16 Nov 2024 23:34:11 -0500 Subject: [PATCH] Refs #35936 -- Avoided field placeholder lookup for each value inserted. By building the list of placeholders for each inserted fields once it doesn't have to be looked up for each inserted rows twice. The query_values_10000.benchmark.QueryValues10000.time_query_values_10000 ASV benchmark showed a 5% speed up for 10k items on SQLite for a single field insertion. Larger performance gains are expected when more fields are involved. --- django/db/models/sql/compiler.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 053bdc09d5..49c5d301cc 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1688,7 +1688,7 @@ class SQLInsertCompiler(SQLCompiler): returning_fields = None returning_params = () - def field_as_sql(self, field, val): + def field_as_sql(self, field, get_placeholder, val): """ Take a field and a value intended to be saved on that field, and return placeholder SQL and accompanying params. Check for raw values, @@ -1703,10 +1703,10 @@ class SQLInsertCompiler(SQLCompiler): elif hasattr(val, "as_sql"): # This is an expression, let's compile it. sql, params = self.compile(val) - elif hasattr(field, "get_placeholder"): + elif get_placeholder is not None: # Some fields (e.g. geo fields) need special munging before # they can be inserted. - sql, params = field.get_placeholder(val, self, self.connection), [val] + sql, params = get_placeholder(val, self, self.connection), [val] else: # Return the common case for the placeholder sql, params = "%s", [val] @@ -1775,8 +1775,12 @@ class SQLInsertCompiler(SQLCompiler): # list of (sql, [params]) tuples for each object to be saved # Shape: [n_objs][n_fields][2] + get_placeholders = [getattr(field, "get_placeholder", None) for field in fields] rows_of_fields_as_sql = ( - (self.field_as_sql(field, v) for field, v in zip(fields, row)) + ( + self.field_as_sql(field, get_placeholder, value) + for field, get_placeholder, value in zip(fields, get_placeholders, row) + ) for row in value_rows )