항상 페이지네이션을 적용하는 키워드 검색(제목/태그), 카테고리 검색 기능을 구현했다.
// 전체 리스트 가져오기
Page<PrfPost> findAll(Pageable pageable);
// 키워드 검색 (태그/제목)
Page<PrfPost> findByTagsContainingOrTitleContaining(Pageable pageable, String keyword1, String keyword2);
// 카테고리 + 키워드 검색
@Query("select p from PrfPost p where p.category=:category and (p.tags like %:keyword% or p.title like %:keyword%)")
Page<PrfPost> findByCategoryAndKeyword(Pageable pageable, String category, String keyword);
💡 INDEX를 설정해서 성능을 높여보자!
현재는 H2를 사용하고 있었는데 더미데이터를 넣기 전에 MySQL로 변경해주었다.
JPA ddl-auto 시, 더미데이터 생성 방법
H2의 종류
더미데이터를 생성하는 방법은 찾아보니까 여러 방법이 있다.
Mysql 프로시저와 mockaroo를 사용해서 더미데이터를 넣기로 결정했다.
mockaroo에서 무료는 최대 1000건까지 생성할 수 있기 때문에 약간의 노가다는 필요하나 여러 데이터 타입이 있어 email이나 전화번호 이런 format을 굳이 내가 설정할 필요가 없었고 랜덤으로 값을 잘 넣어주기 때문에 사용하기에 유의미한 값들을 넣어주기에 좋다고 생각했다.
나와 비슷한 선택을 한 블로그도 보았다.
구현해놓은 검색이나 카테고리 기능도 테스트해봐야 하기 때문에 더미데이터의 값도 어느정도는 설계하고 가야겠다고 생각했다.

따라서 category, tags, title, like_count에 의미있는 값을 주어야 한다.
like_count은 0과 10 사이의 랜덤한 정수값으로 category, tags, title은 다음과 같은 키워드들이 들어가도록 더미데이터를 설계했다.
3만건들은 검색과 정렬 기능을 테스트할 수 있도록 유의미한 데이터를, 나머지 700만건은 dummy data를 넣어줄 것이다.

✔️ member 프로시저
DELIMITER $$
DROP PROCEDURE IF EXISTS memberInsert$$
CREATE PROCEDURE memberInsert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 1000000 DO
insert into member (CREATED_AT, MODIFIED_AT, email, member_status, nick_name, password) values (now(), now(), concat('userid@',i,'naver.com'), 'ACTIVE', concat('nickname',i), 'password');
SET i = i + 1;
END WHILE;
END$$
DELIMITER $$
CALL memberInsert; $$
✔️ prf_post 프로시저
DELIMITER $$
DROP PROCEDURE IF EXISTS loopInsert$$
CREATE PROCEDURE loopInsert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 1000000 DO
insert into prf_post (CREATED_AT, MODIFIED_AT, CATEGORY, CONTENT, like_count, TAGS, TITLE , MEMBER_ID) values (now(), now(), '맛집', '내용', 0, '#검색#인덱스#잘되나', '맛집 게시글입니다.', 2);
insert into prf_post (CREATED_AT, MODIFIED_AT, CATEGORY, CONTENT, like_count, TAGS, TITLE , MEMBER_ID) values (now(), now(), '영화', '내용', 0, '#검색#인덱스#잘되나', '영화 게시글', 2);
insert into prf_post (CREATED_AT, MODIFIED_AT, CATEGORY, CONTENT, like_count, TAGS, TITLE , MEMBER_ID) values (now(), now(), '음악', '내용', 0, '#검색#인덱스#잘되나', '음악 게시글', 2);
SET i = i + 1;
END WHILE;
END$$
DELIMITER $$
CALL loopInsert; $$
DELIMITER $$에서 DELIMITER과 $$ 사이에 공백이 필요하다!select * from prf_post order by id DESC;
// 0.0023 sec
select * from prf_post order by like_count DESC, id DESC;
// 11.439 sec
hibernate, mysql 등은 기본적으로 기본키를 활용한 인덱스 테이블을 자동으로 만든다.
인덱스를 적용할 곳은 정렬과 검색이다.
인덱스를 설정해둔다고 해서 무조건 인덱스를 다 타는 것이 아니다. 오히려 안 타는 경우가 많다!
https://jmkim.tistory.com/66
https://weicomes.tistory.com/191
https://jojoldu.tistory.com/481

- 태그(tags)에 인덱스를 설정
#검색#인덱스#잘되나라는 태그가 9120000개 있다.#성수#화양라는 태그는 6개 있다.
1. select * from prf_post where tags like "#검색%";
-> 인덱스를 타지 않는다!
원래 마지막에 %를 붙이면 인덱스를 타야하는데, 인덱스는 결과값이 1/3 미만일 경우에만 인덱스를 타기 때문에 인덱스를 타지 않는 것이다.
2. select count(*) from prf_post where tags like "%#검색%";
-> 인덱스를 안 탄다.
3. select * from prf_post where tags like "#성수%";
-> 인덱스를 탄다.
[참고]
https://jojoldu.tistory.com/476
https://choicode.tistory.com/27
https://k3068.tistory.com/106
https://jojoldu.tistory.com/243
https://jaehoney.tistory.com/98#:~:text=%EC%9D%B8%EB%8D%B1%EC%8A%A4%EB%A5%BC%20%ED%83%80%EB%8A%94%20%EC%A7%80%20%ED%99%95%EC%9D%B8,explain%EC%9D%84%20%EB%B6%99%EC%97%AC%EC%A3%BC%EB%A9%B4%20%EB%90%A9%EB%8B%88%EB%8B%A4.
https://velog.io/@ljinsk3/JPA%EB%A1%9C-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
https://wrkbr.tistory.com/559
https://zorba91.tistory.com/292
http://www.gurubee.net/article/58340