HwangHub

[리팩토링] post 엔티티 body 필드 TEXT 적용 본문

PROJECT-LOG/likelion.university

[리팩토링] post 엔티티 body 필드 TEXT 적용

HwangJerry 2023. 10. 13. 15:13

문제 상황

기존에 작업에서는 게시글 엔티티가 아래와 같이 선언되어 있었다.

@Entity
public class Post extends BaseTimeEntity {

	...

    @Column(length = 500)
    private String title;

    @Column(length = 50000)
    private String body;

    ...

}

본문 필드에 50000으로 받겠다고 선언되어있었는데, 이는 일반적이지 않은 선언이다. 우선 mysql 기준 레코드 전체 크기가 65,535 bytes로 제한되어 있으므로, 50000과 같은 길이 설정 자체에서 오류를 일으키기도 하고, 그것 외에도 실제 생성하면서도 레코드가 생성되지 않고 에러를 발생시킬 수 있기 때문이다.

 

반면, 일반적으로 긴 문자열을 저장하기 위해 사용되는 TEXT 설정값은 기본적으로 off-page라는 영역에 데이터를 저장하기 때문에 이러한 걱정으로부터 자유로워질 수 있다.

 

그렇다면 모든 문자열 필드를 TEXT로 선언하면 되는 것 아닌가?

 

그렇지 않다.

 

길이가 일정 수준을 넘어간 varchar와 TEXT는 off-page라는 영역에 저장되는데, 이 곳은 기본적으로 mysql 엔진이 포인터를 이용하여 레코드를 가리키고 있는 영역 외의 공간이기 때문에, 이 데이터를 불러오기 위해서 추가적으로 매번 메모리를 할당해줘야 하며, 이는 성능에 영향을 미치는데 이를 가늠하기가 어렵다.

 

따라서 상대적으로 작은 길이의 데이터 중 반드시 조회해야 하는 성격의 데이터들은 보통 varchar로 선언하는 것이 권장되며, 길이가 대체적으로 항상 길 것으로 예상되는 데이터라면 일단 TEXT로 선언하는 것을 고려해야 한다.

 

중요한 점은, 필요에 따라 의도를 갖고 선언해줘야 한다는 것이다. (개인적 사견을 더하자면, 만약 계속 조회해야 하는 데이터인데, 항상 그 길이가 길어야 하는 게 아니라면 그냥 서비스 기획 단에서 길이를 제한해버리고 varchar로 활용하면 어떨까 싶다.)

JPA를 이용하여 String 타입의 DB 칼럼을 선언할 때, 별도로 length를 설정하지 않으면 default로 varchar(255)로 설정되며, 기입되는 길이값이 있다면 그대로 반영된다. (여기서 255와 같은 숫자는 글자수와 동치하여 이해하면 된다.)

varchar의 기본값이 255인 이유는, mysql 버전 5.0.3 이전까지는 varchar의 최대 길이는 255 bytes였다고 한다. 5.0.3부터는 0 to 65535 bytes라고 한다. (현재는 char만 0 to 255이다.)

주의할 점은, varchar는 255 전까지는 length를 해석하기 위한 prefix byte가 1byte 필요한데, 255 이후부터는 2 bytes가 필요하다고 한다. 이는 사전에 필드 설정을 만약 255보다 작은 크기로 설정해뒀을 때에는 255까지는 확장하는 것이 무리가 아니지만, 255를 넘기도록 설정하려면 데이터 구조가 변경되어야 해서 제한이 있을 수 있다고 한다. 따라서 이에 유의하여 처음에 DB 구조를 설계해야 할 것이다.

참고: https://dev.mysql.com/doc/refman/8.0/en/char.html 참고: https://velog.io/@sunaookamisiroko/MySQL-varchar255를-사용하는-이유

 

결론

  • 제목은 50자로 제한하기로 했다.
  • 본문 내용은 json 형식일 필요가 없으므로 @Column(columnDefinition=”TEXT”)로 선언해두어 저장하기로 했다.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
@AllArgsConstructor
@Entity
public class Post extends BaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "post_id")
    private Long id;

    @Column(length = 500)
    private String title;

    @Column(columnDefinition=”TEXT”)
    private String body;

		...

}

 

참고: https://www.baeldung.com/jpa-size-length-column-differences

참고: https://leezzangmin.tistory.com/49

참고: https://medium.com/daangn/varchar-vs-text-230a718a22a1

참고: https://medium.com/daangn/json-vs-text-c2c1448b8b1f

참고: https://dev.mysql.com/doc/refman/8.0/en/char.html

참고: https://velog.io/@sunaookamisiroko/MySQL-varchar255를-사용하는-이유

 

Comments