| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
- Failed to load ApplicationContext
- #mojo
- sftp
- Maven
- postgres
- spring boot
- QGIS
- mysql
- postgresql
- posgis
- Java
- python
- Geoserver
- uuid
- spring
- Spring Security
- nginx
- Docker
- JSON Web Token
- RDB
- AuthenticationPrincipal
- psycopg2
- Kafka
- Linux
- LazyInitializationException
- JWT
- insert into
- hadoop #hdfs
- JPA
- 1093
- Today
- Total
FOREST_CHOI's BLOG
JPA OrderBy rand() Issue 본문
Querydsl 을 사용하면서 랜덤값을 추출 해야할 경우가 생겼다.
일단 나는 아래와 같이 native Query를 Querydsl에도 적용하려고 해 보았다.
@Query(value = "select * from building order by RAND() limit 1", nativeQuery = true)
public Optional<Building> findBuilding();
public Optional<Building> findBuilding() {
Building building = jpaQueryFactory
.selectFrom(QBuilding.building)
.orderby({_____})
.limit(1)
.fetch();
return Optional.ofNullable(building);
}
orderby 중괄호가 된 부분에 building.id.rand() 형태로 넣어 줄 수 있는 지 알았다.
하지만, jpa에서 제공하지 않는 문법이기 때문에 당연히 querydsl에서 도 지원을 하지 않는 것 이었다.

결정적으로 일단 이정도만 지원한다.
하지만 저렇게 rand하여 값을 가져오는데는 문제가 있다는 결론에 달았다.
일단, 첫번 째 native query를 다시 볼 필요가 있다.
@Query(value = "select * from building order by RAND() limit 1", nativeQuery = true)
일단 기본적으로 RAND() 함수는 쿼리 실행 순간에 레코드에 각각 임의의 값을 할당 후 그 값으로 정렬을 수행하게 되는데, 비용이 아주 큰연산이다. 또한 order by 조건에 인덱스를 활용할 수 있는 조건이 아니면 모든 조건은 비효율적이라고 생각하면 된다.
** 결국 비효율적인 방법이라는 것이다.!!!
이에 대한 해결책으로 CountAll 하여 row의 개수를 가져오고 여기서 Java의 Random함수를 통해 랜덤값을 가져올 수 있는 방법을 택하였다.
public Optional<Building> findRandomBuilding(){
Long count = buildingRepository.countAll();
int randomIndex = (int)(Math.random() * count);
return Optional.ofNullable(jpaQueryFactory
.selectFrom(QBuilding.building)
.where(building.id.eq(randomIndex))
.limit(1)
.fetch());
}
그나마 개선한 작업이 이 메서드였다. 랜덤한 pk로 값을 가져올 수 있어서 될 것 같았지만 만약 삭제된 Pk라면?????? null을 반환하게 될 것이다. ㅠㅠ
결국 마지막에는 구글링을 통해 가져 왔는데, 페이징 처리를 통하여 랜덤 페이지 1개를 찾고 그 중 하나의 값을 가져오는 로직으로 바꾸었다.
public Optional<Building> findRandomBuilding(){
Long count = buildingRepository.countAll();
int randomIndex = (int)(Math.random() * count);
Page<Building> buildingPage = questionRepository.findAll(new PageRequest(idx, 1));
Building building = null;
if (buildingPage.hasContent()) {
building = buildingPage.getContent().get(0);
}
return Optional.ofNullable(building);
}
아래 StackOverFlow에서 정보를 얻을 수 있었다.
https://stackoverflow.com/questions/24279186/fetch-random-records-using-spring-data-jpa
Fetch random records using Spring data JPA
I want to fetch random records using Spring data JPA. I was using @Query for the same.But it is taking a long time. @Query("select que from Question que order by RAND()") public List<Question>
stackoverflow.com
'프로그래밍 > JPA' 카테고리의 다른 글
| Querydsl의 FetchJoin 과 DTO (0) | 2022.12.22 |
|---|---|
| @Embedded, @Embeddable (0) | 2022.10.20 |
| JPA? (0) | 2022.10.16 |
| data.sql / insert 구문 시 pk 안들어가는 문제 (0) | 2022.09.23 |
| org.h2.jdbc.JdbcSQLDataException: Hexadecimal string contains non-hex character (0) | 2022.09.20 |