Server๐Ÿงค/QueryDsl

[Querydsl] ๋ฌดํ•œ ์Šคํฌ๋กค ๊ธฐ๋Šฅ ๊ตฌํ˜„ ( Offset vs No Offest )

yujindonut 2023. 6. 28. 00:20
728x90

Soptmakers์—์„œ, ๋๋ง์ž‡๊ธฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค. ์ฒ˜์Œ MVP๋Š” ๋ชจ๋“  ํšŒ์ฐจ์˜ ๋๋ง์ž‡๊ธฐ ๋ชฉ๋ก์„ ๋ณด์ด๋„๋ก ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

๋ฌดํ•œ ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ• ๋•Œ๋Š” limit, cursor, hasNext์™€ ๊ฐ™์€ ํ•„๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • limit : ํŽ˜์ด์ง€ ์‚ฌ์ด์ฆˆ
  • cursor: ์ฝ๊ณ  ์‹ถ์€ ํ–‰์˜ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜
  • hasNext: ์Šคํฌ๋กค ์ดํ›„ ๊ทธ ๋’ค์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์•„์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ํŒ๋‹จํ•˜๋Š” ํ•„๋“œ

๋ฌธ์ œ์  ๋ฐœ์ƒ

์ „์ฒด ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ์—, ์ค‘๋ณต๋˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณด์ด๊ฒŒ๋จ

limit์€ 10

cursor๋Š” 10, 20, 30~ ์˜ ๊ฐ’์œผ๋กœ ์š”์ฒญ

์ด ๊ณผ์ •์—์„œ, (0 ~ 10) (10 ~ 20) (20 ~ 30) ์ค‘๊ฐ„์˜ ๊ฐ’๋“ค์ด ์ค‘๋ณต๋˜๋Š” ํ˜„์ƒ ๋ฐœ์ƒ


๐Ÿ“Offest Based Pagination

@Repository
@RequiredArgsConstructor
public class WordChainGameQueryRepository {

    private final JPAQueryFactory queryFactory;

    public List<WordChainGameRoom> findAllLimitedGameRoom(
            Integer limit, Integer cursor
    ) {
        val room = QWordChainGameRoom.wordChainGameRoom;
        return queryFactory.selectFrom(room)
                .offset(cursor)
                .limit(limit)
                .orderBy(room.id.desc())
                .groupBy(room.id)
                .fetch();
    }
}

cursor์— ํ•ด๋‹นํ•˜๋Š” ๋งŒํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๋“ค์ธ ํ›„ limit ๋งŒํผ์˜ ํ–‰์„ ์ฝ๊ณ  ์•ž์— ์ต์€ ํ–‰์„ ์‚ญ์ œํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋งŽ์•„์งˆ ์ˆ˜๋ก ์ฝ์–ด์•ผํ•  ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๊ฒŒ ๋˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋งŽ์€ ๋ถ€ํ•˜๊ฐ€ ์ƒ๊ฒจ ์†๋„ ๋ฉด์—์„œ๋„ ๋Š๋ ค์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘๊ฐ„์— ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฝ์ž…๋˜๋ฉด, ์ด์ „ ํŽ˜์ด์ง€์™€ ์ค‘๋ณต๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

order by id desc

์ตœ์‹ ์—์„œ ๊ณผ๊ฑฐ์ˆœ์œผ๋กœ ์กฐํšŒ

์•ž์—์„œ ์ฝ์—ˆ๋˜ ํ–‰์„ ๋‹ค์‹œ ์ฝ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๊ฐ€ ๋’ค๋กœ ๊ฐˆ์ˆ˜๋ก ๋Š๋ ค์ง‘๋‹ˆ๋‹ค. 

์˜ˆ) offset 10000, limit 10 -? 10010๊ฐœ์˜ ํ–‰์„ ์ฝ๊ณ  10000๊ฐœ์˜ ํ–‰์€ ๋ฒ„๋ฆผ.

 

๐Ÿ“No Offest , Cursor Based Pagination

์กฐํšŒ ์‹œ์ž‘ ๋ถ€๋ถ„์„ ์ธ๋ฑ์Šค๋กœ ๋น ๋ฅด๊ฒŒ ์ฐพ์•„, ๋งค๋ฒˆ ์ฒซ ํŽ˜์ด์ง€๋งŒ ์ฝ๋„๋ก ํ•˜๋Š” ๋ฐฉ์‹.

๋งˆ์ง€๋ง‰ ์กฐํšŒํ•œ ํ–‰์˜ id ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ, ์ฝ์ง€ ์•Š์€ ํ–‰์„ page size ๋งŒํผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. id๋ผ๋Š” ํด๋Ÿฌ์Šคํ„ฐ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์ž‘ ๋ถ€๋ถ„์„ ๋น ๋ฅด๊ฒŒ ์ฐพ์•„ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ(offset)๊ฐ€ ์—†๋Š” ๋”๋ณด๊ธฐ ๋ฐฉ์‹.

 

ํ”„๋ก ํŠธ ๊ฐœ๋ฐœ์ž๋‹˜๊ป˜ cursor๋ฅผ ์กฐํšŒ๋œ ๋งˆ์ง€๋ง‰ id๋ฅผ ์ „์†กํ•ด๋‹ฌ๋ผ๊ณ  ์ˆ˜์ •์‚ฌํ•ญ์„ ์š”์ฒญ

์ฒซ ์กฐํšŒ๋Š” cursor์— 0์„ ๋ณด๋‚ด๋„๋ก ์š”์ฒญ

public List<WordChainGameRoom> findAllLimitedGameRoom(Integer limit, Long cursor) {
	val room = QWordChainGameRoom.wordChainGameRoom;
	return queryFactory.selectFrom(room)
		.where(ltGameRoomId(cursor))
		.limit(limit)
		.orderBy(room.id.desc())
		.groupBy(room.id)
		.fetch();
}

private BooleanExpression ltGameRoomId(Long gameRoomId) {
	val room = QWordChainGameRoom.wordChainGameRoom;
	if(gameRoomId == null || gameRoomId == 0) return null;
		return room.id.lt(gameRoomId);
}

 

๐Ÿ‘€ Cursor Based Pagination์˜ ํ•œ๊ณ„์ 

cursor๊ฐ’์€ ์ˆœ์ฐจ์ ์ด์–ด์•ผํ•˜๋ฉฐ, ์ •๋ ฌ์— ํฌํ•จ๋˜๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ํ•„๋“œ๋Š” unique ํ•ด์•ผํ•œ๋‹ค.

offset ๋ฐฉ์‹ ๊ฐ™์€ ๊ฒฝ์šฐ, ์Šคํ‚ตํ•  ๋ฐ์ดํ„ฐ ์ˆ˜์™€ limit๊ฐ’๋งŒ ์ฃผ์–ด์ง„๋‹ค๋ฉด ์–ด๋–ค ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ด๋„ ํŽ˜์ด์ง•์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ cursor ๋ฐฉ์‹์€ ๋” ๋งŽ์€ ์ œ์•ฝ์„ ๊ฐ€์ง„๋‹ค.

728x90