Skip to content

Commit 9d8455f

Browse files
committed
Improve count and exists query projections.
We now use COUNT(*) and SELECT 1 for count respective exists queries to enable database optimizers instead of using the key columns. Closes #1647
1 parent f8477ad commit 9d8455f

File tree

3 files changed

+8
-23
lines changed

3 files changed

+8
-23
lines changed

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplate.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -247,18 +247,11 @@ public Mono<Long> count(Query query, Class<?> entityClass) throws DataAccessExce
247247

248248
Mono<Long> doCount(Query query, Class<?> entityClass, SqlIdentifier tableName) {
249249

250-
RelationalPersistentEntity<?> entity = getRequiredEntity(entityClass);
251250
StatementMapper statementMapper = dataAccessStrategy.getStatementMapper().forType(entityClass);
252251

253252
StatementMapper.SelectSpec selectSpec = statementMapper //
254253
.createSelect(tableName) //
255-
.doWithTable((table, spec) -> {
256-
257-
Expression countExpression = entity.hasIdProperty()
258-
? table.column(entity.getRequiredIdProperty().getColumnName())
259-
: Expressions.just("1");
260-
return spec.withProjection(Functions.count(countExpression));
261-
});
254+
.withProjection(Functions.count(Expressions.just("*")));
262255

263256
Optional<CriteriaDefinition> criteria = query.getCriteria();
264257
if (criteria.isPresent()) {
@@ -284,17 +277,9 @@ public Mono<Boolean> exists(Query query, Class<?> entityClass) throws DataAccess
284277

285278
Mono<Boolean> doExists(Query query, Class<?> entityClass, SqlIdentifier tableName) {
286279

287-
RelationalPersistentEntity<?> entity = getRequiredEntity(entityClass);
288280
StatementMapper statementMapper = dataAccessStrategy.getStatementMapper().forType(entityClass);
289-
290-
StatementMapper.SelectSpec selectSpec = statementMapper.createSelect(tableName).limit(1);
291-
if (entity.hasIdProperty()) {
292-
selectSpec = selectSpec //
293-
.withProjection(entity.getRequiredIdProperty().getColumnName());
294-
295-
} else {
296-
selectSpec = selectSpec.withProjection(Expressions.just("1"));
297-
}
281+
StatementMapper.SelectSpec selectSpec = statementMapper.createSelect(tableName).limit(1)
282+
.withProjection(Expressions.just("1"));
298283

299284
Optional<CriteriaDefinition> criteria = query.getCriteria();
300285
if (criteria.isPresent()) {

spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplateUnitTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ void shouldCountBy() {
104104

105105
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
106106

107-
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(person.id) FROM person WHERE person.THE_NAME = $1");
107+
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(*) FROM person WHERE person.THE_NAME = $1");
108108
assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter"));
109109
}
110110

@@ -145,7 +145,7 @@ void shouldProjectCountResultWithoutId() {
145145

146146
MockResult result = MockResult.builder().row(MockRow.builder().identified(0, Long.class, 1L).build()).build();
147147

148-
recorder.addStubbing(s -> s.startsWith("SELECT COUNT(1)"), result);
148+
recorder.addStubbing(s -> s.startsWith("SELECT COUNT(*)"), result);
149149

150150
entityTemplate.select(WithoutId.class).count() //
151151
.as(StepVerifier::create) //
@@ -169,7 +169,7 @@ void shouldExistsByCriteria() {
169169

170170
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
171171

172-
assertThat(statement.getSql()).isEqualTo("SELECT person.id FROM person WHERE person.THE_NAME = $1 LIMIT 1");
172+
assertThat(statement.getSql()).isEqualTo("SELECT 1 FROM person WHERE person.THE_NAME = $1 LIMIT 1");
173173
assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter"));
174174
}
175175

spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ void shouldSelectExists() {
193193

194194
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
195195

196-
assertThat(statement.getSql()).isEqualTo("SELECT person.id FROM person WHERE person.THE_NAME = $1 LIMIT 1");
196+
assertThat(statement.getSql()).isEqualTo("SELECT 1 FROM person WHERE person.THE_NAME = $1 LIMIT 1");
197197
}
198198

199199
@Test // gh-220
@@ -216,7 +216,7 @@ void shouldSelectCount() {
216216

217217
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
218218

219-
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(person.id) FROM person WHERE person.THE_NAME = $1");
219+
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(*) FROM person WHERE person.THE_NAME = $1");
220220
}
221221

222222
static class Person {

0 commit comments

Comments
 (0)