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
This commit is contained in:
@@ -253,18 +253,11 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
|
||||
Mono<Long> doCount(Query query, Class<?> entityClass, SqlIdentifier tableName) {
|
||||
|
||||
RelationalPersistentEntity<?> entity = getRequiredEntity(entityClass);
|
||||
StatementMapper statementMapper = dataAccessStrategy.getStatementMapper().forType(entityClass);
|
||||
|
||||
StatementMapper.SelectSpec selectSpec = statementMapper //
|
||||
.createSelect(tableName) //
|
||||
.doWithTable((table, spec) -> {
|
||||
|
||||
Expression countExpression = entity.hasIdProperty()
|
||||
? table.column(entity.getRequiredIdProperty().getColumnName())
|
||||
: Expressions.just("1");
|
||||
return spec.withProjection(Functions.count(countExpression));
|
||||
});
|
||||
.withProjection(Functions.count(Expressions.just("*")));
|
||||
|
||||
Optional<CriteriaDefinition> criteria = query.getCriteria();
|
||||
if (criteria.isPresent()) {
|
||||
@@ -290,17 +283,9 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
|
||||
Mono<Boolean> doExists(Query query, Class<?> entityClass, SqlIdentifier tableName) {
|
||||
|
||||
RelationalPersistentEntity<?> entity = getRequiredEntity(entityClass);
|
||||
StatementMapper statementMapper = dataAccessStrategy.getStatementMapper().forType(entityClass);
|
||||
|
||||
StatementMapper.SelectSpec selectSpec = statementMapper.createSelect(tableName).limit(1);
|
||||
if (entity.hasIdProperty()) {
|
||||
selectSpec = selectSpec //
|
||||
.withProjection(entity.getRequiredIdProperty().getColumnName());
|
||||
|
||||
} else {
|
||||
selectSpec = selectSpec.withProjection(Expressions.just("1"));
|
||||
}
|
||||
StatementMapper.SelectSpec selectSpec = statementMapper.createSelect(tableName).limit(1)
|
||||
.withProjection(Expressions.just("1"));
|
||||
|
||||
Optional<CriteriaDefinition> criteria = query.getCriteria();
|
||||
if (criteria.isPresent()) {
|
||||
|
||||
@@ -100,7 +100,7 @@ public class R2dbcEntityTemplateUnitTests {
|
||||
|
||||
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
|
||||
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(person.id) FROM person WHERE person.THE_NAME = $1");
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(*) FROM person WHERE person.THE_NAME = $1");
|
||||
assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter"));
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public class R2dbcEntityTemplateUnitTests {
|
||||
|
||||
MockResult result = MockResult.builder().row(MockRow.builder().identified(0, Long.class, 1L).build()).build();
|
||||
|
||||
recorder.addStubbing(s -> s.startsWith("SELECT COUNT(1)"), result);
|
||||
recorder.addStubbing(s -> s.startsWith("SELECT COUNT(*)"), result);
|
||||
|
||||
entityTemplate.select(WithoutId.class).count() //
|
||||
.as(StepVerifier::create) //
|
||||
@@ -165,7 +165,7 @@ public class R2dbcEntityTemplateUnitTests {
|
||||
|
||||
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
|
||||
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT person.id FROM person WHERE person.THE_NAME = $1 LIMIT 1");
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT 1 FROM person WHERE person.THE_NAME = $1 LIMIT 1");
|
||||
assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter"));
|
||||
}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ public class ReactiveSelectOperationUnitTests {
|
||||
|
||||
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
|
||||
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT person.id FROM person WHERE person.THE_NAME = $1 LIMIT 1");
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT 1 FROM person WHERE person.THE_NAME = $1 LIMIT 1");
|
||||
}
|
||||
|
||||
@Test // gh-220
|
||||
@@ -239,7 +239,7 @@ public class ReactiveSelectOperationUnitTests {
|
||||
|
||||
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT"));
|
||||
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(person.id) FROM person WHERE person.THE_NAME = $1");
|
||||
assertThat(statement.getSql()).isEqualTo("SELECT COUNT(*) FROM person WHERE person.THE_NAME = $1");
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
Reference in New Issue
Block a user