diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 4fae947883..ba197c818e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -534,6 +534,7 @@ spring.servlet.multipart.max-file-size: "50MB" spring.servlet.multipart.max-request-size: "50MB" spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" +# Note: as for current Spring JPA version, custom NullHandling for the Sort.Order is ignored and this parameter is used spring.jpa.properties.hibernate.order_by.default_null_ordering: "${SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING:last}" # SQL DAO Configuration diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractChunkedAggregationTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractChunkedAggregationTimeseriesDao.java index 22c4661fcd..cf726c32c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractChunkedAggregationTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractChunkedAggregationTimeseriesDao.java @@ -20,7 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.Aggregation; @@ -143,8 +143,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq keyId, query.getStartTs(), query.getEndTs(), - PageRequest.of(0, query.getLimit(), - Sort.by(new Sort.Order(Sort.Direction.fromString(query.getOrder()), "ts").nullsNative()))); + PageRequest.ofSize(query.getLimit()).withSort(Direction.fromString(query.getOrder()), "ts")); tsKvEntities.forEach(tsKvEntity -> tsKvEntity.setStrKey(query.getKey())); List tsKvEntries = DaoUtil.convertDataList(tsKvEntities); long lastTs = tsKvEntries.stream().map(TsKvEntry::getTs).max(Long::compare).orElse(query.getStartTs()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java index 6e9f9e61b8..c9daf1ec6d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java @@ -175,9 +175,7 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements keyId, query.getStartTs(), query.getEndTs(), - PageRequest.of(0, query.getLimit(), - Sort.by(new Sort.Order(Sort.Direction.fromString(query.getOrder()), "ts").nullsNative()))); - ; + PageRequest.ofSize(query.getLimit()).withSort(Sort.Direction.fromString(query.getOrder()), "ts")); timescaleTsKvEntities.forEach(tsKvEntity -> tsKvEntity.setStrKey(strKey)); var tsKvEntries = DaoUtil.convertDataList(timescaleTsKvEntities); long lastTs = tsKvEntries.stream().map(TsKvEntry::getTs).max(Long::compare).orElse(query.getStartTs()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TsKvTimescaleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TsKvTimescaleRepository.java index 075cffcbc7..821833cad0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TsKvTimescaleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TsKvTimescaleRepository.java @@ -31,14 +31,13 @@ import java.util.UUID; @TimescaleDBTsOrTsLatestDao public interface TsKvTimescaleRepository extends JpaRepository { - @Query("SELECT tskv FROM TimescaleTsKvEntity tskv WHERE tskv.entityId = :entityId " + - "AND tskv.key = :entityKey " + - "AND tskv.ts >= :startTs AND tskv.ts < :endTs") - List findAllWithLimit( - @Param("entityId") UUID entityId, - @Param("entityKey") int key, - @Param("startTs") long startTs, - @Param("endTs") long endTs, Pageable pageable); + @Query(value = "SELECT * FROM ts_kv WHERE entity_id = :entityId " + + "AND key = :entityKey AND ts >= :startTs AND ts < :endTs", nativeQuery = true) + List findAllWithLimit(@Param("entityId") UUID entityId, + @Param("entityKey") int key, + @Param("startTs") long startTs, + @Param("endTs") long endTs, + Pageable pageable); @Transactional @Modifying diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/TsKvRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/TsKvRepository.java index 1d9817a5bd..66d619d0ea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/TsKvRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/TsKvRepository.java @@ -29,8 +29,15 @@ import java.util.UUID; public interface TsKvRepository extends JpaRepository { - @Query("SELECT tskv FROM TsKvEntity tskv WHERE tskv.entityId = :entityId " + - "AND tskv.key = :entityKey AND tskv.ts >= :startTs AND tskv.ts < :endTs") + /* + * Using native query to avoid adding 'nulls first' or 'nulls last' (ignoring spring.jpa.properties.hibernate.order_by.default_null_ordering) + * to the order so that index scan is done instead of full scan. + * + * Note: even when setting custom NullHandling for the Sort.Order for non-native queries, + * it will be ignored and default_null_ordering will be used + * */ + @Query(value = "SELECT * FROM ts_kv WHERE entity_id = :entityId " + + "AND key = :entityKey AND ts >= :startTs AND ts < :endTs ", nativeQuery = true) List findAllWithLimit(@Param("entityId") UUID entityId, @Param("entityKey") int key, @Param("startTs") long startTs,