From 4b672412a1b8ad8cd7cbe22673e74d2eb345cebf Mon Sep 17 00:00:00 2001 From: Mikhail Fedorov Date: Thu, 1 May 2025 03:46:14 +0300 Subject: [PATCH 1/5] Fix performance bug with large number of unnamed parameters On some occasions where col in (:args) contain a really lot args, 10k+ for instance, this commit fixes a performance (high CPU) bug by NOT traversing the whole map in basically O(n^2) manner Signed-off-by: Mikhail Fedorov --- .../data/jdbc/core/convert/QueryMapper.java | 14 +++++--------- .../jdbc/core/convert/QueryMapperUnitTests.java | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java index 8bbc44dd12..d87c9b1e91 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java @@ -625,20 +625,16 @@ private Expression bind(@Nullable Object mappedValue, SQLType sqlType, MapSqlPar } private static String getUniqueName(MapSqlParameterSource parameterSource, String name) { - - Map values = parameterSource.getValues(); - - if (!values.containsKey(name)) { + Map parameters = parameterSource.getValues(); + Object existingName = parameters.get(name); + if (existingName == null) { return name; } - - int counter = 1; + int counter = parameters.size(); String uniqueName; - do { uniqueName = name + (counter++); - } while (values.containsKey(uniqueName)); - + } while (parameters.containsKey(uniqueName)); return uniqueName; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java index d7ad16364c..9477f4dfdd 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java @@ -121,7 +121,7 @@ public void shouldMapNestedGroup() { Condition condition = map(criteria); assertThat(condition).hasToString( - "(person.\"NAME\" = ?[:name]) AND (person.\"NAME\" = ?[:name1] OR person.age < ?[:age] OR (person.\"NAME\" != ?[:name2] AND person.age > ?[:age1]))"); + "(person.\"NAME\" = ?[:name]) AND (person.\"NAME\" = ?[:name1] OR person.age < ?[:age] OR (person.\"NAME\" != ?[:name3] AND person.age > ?[:age4]))"); } @Test // DATAJDBC-318 From 9b78e3c60edbaceea186899e618b96c0407e9bce Mon Sep 17 00:00:00 2001 From: Mikhail Fedorov Date: Thu, 1 May 2025 03:46:14 +0300 Subject: [PATCH 2/5] Fix performance bug with large number of unnamed parameters On some occasions where col in (:args) contain a really lot args, 10k+ for instance, this commit fixes a performance (high CPU) bug by NOT traversing the whole map in basically O(n^2) manner Signed-off-by: Mikhail Fedorov --- .../data/jdbc/core/convert/QueryMapperUnitTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java index 9477f4dfdd..a67da7397f 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java @@ -46,6 +46,7 @@ * * @author Mark Paluch * @author Jens Schauder + * @author Mikhail Fedorov */ public class QueryMapperUnitTests { From 8b63319d61a6da2d67a2adb7c95a6a1a941053a1 Mon Sep 17 00:00:00 2001 From: Mikhail Fedorov Date: Thu, 1 May 2025 03:46:15 +0300 Subject: [PATCH 3/5] Fix performance bug with large number of unnamed parameters On some occasions where col in (:args) contain a really lot args, 10k+ for instance, this commit fixes a performance (high CPU) bug by NOT traversing the whole map in basically O(n^2) manner Signed-off-by: Mikhail Fedorov --- .../data/jdbc/core/convert/QueryMapper.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java index d87c9b1e91..b8915ad7b1 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java @@ -625,16 +625,19 @@ private Expression bind(@Nullable Object mappedValue, SQLType sqlType, MapSqlPar } private static String getUniqueName(MapSqlParameterSource parameterSource, String name) { - Map parameters = parameterSource.getValues(); - Object existingName = parameters.get(name); - if (existingName == null) { + + Map values = parameterSource.getValues(); + + if (!values.containsKey(name)) { return name; } - int counter = parameters.size(); + + int counter = values.size(); String uniqueName; + do { uniqueName = name + (counter++); - } while (parameters.containsKey(uniqueName)); + } while (values.containsKey(uniqueName)); return uniqueName; } From 7c609c493293ab41aaa6f928ebbeaa3bfd581314 Mon Sep 17 00:00:00 2001 From: Mikhail Fedorov Date: Thu, 1 May 2025 03:46:15 +0300 Subject: [PATCH 4/5] Fix performance bug with large number of unnamed parameters On some occasions where col in (:args) contain a really lot args, 10k+ for instance, this commit fixes a performance (high CPU) bug by NOT traversing the whole map in basically O(n^2) manner Signed-off-by: Mikhail Fedorov --- .../org/springframework/data/jdbc/core/convert/QueryMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java index b8915ad7b1..647aea6813 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java @@ -638,6 +638,7 @@ private static String getUniqueName(MapSqlParameterSource parameterSource, Strin do { uniqueName = name + (counter++); } while (values.containsKey(uniqueName)); + return uniqueName; } From 0f3d34716385ab3f7eecbd6e6563fd8c774f853d Mon Sep 17 00:00:00 2001 From: Mikhail Fedorov Date: Thu, 1 May 2025 03:51:37 +0300 Subject: [PATCH 5/5] Fix performance bug with large number of unnamed parameters On some occasions where col in (:args) contain a really lot args, 10k+ for instance, this commit fixes a performance (high CPU) bug by NOT traversing the whole map in basically O(n^2) manner Signed-off-by: Mikhail Fedorov --- .../org/springframework/data/jdbc/core/convert/QueryMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java index 647aea6813..1d3ce3095e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java @@ -53,6 +53,7 @@ * @author Mark Paluch * @author Jens Schauder * @author Yan Qiang + * @author Mikhail Fedorov * @since 3.0 */ public class QueryMapper {