4 분 소요

판매글 Filtering 개선

상황 설명

우리 팀에서 B2B 건으로 판매글을 직접 등록을 해야하는 상황이었습니다. 판매글을 등록을 하다 보니, 제품 고유의 옵션(길이, 폭 등등)들은 있지만 이는 모든 제품들의 옵션을 커버를 할 수 없는 상황이었습니다.

가구는 타 제품 보다 옵션이 많은 제품입니다. 하나의 제품의 길이, 폭 등등 고유한 옵션들도 있지만 카테고리에 따른 옵션도 많습니다. 저희는 소비자들이 더욱 더 상세한 옵션들을 이용하여 Filtering을 할 수 있게끔 옵션들을 추가 해 주었습니다.

개선 전 해야할 일

  • DB 구조 개선

  1. option table 만들기

    option table을 만드는 이유는 판매글을 등록을 할 때, 카테고리 지정 후 해당 카테고리에 따른 option을 지정할 수 있게끔 만들기 위해 만들었습니다.

    option table을 설계 하면서 한 가지 작은 문제가 생겼습니다.

    카테고리에 대한 옵션을 소분류 카테고리에 붙힐지 중분류 카테고리에 붙힐지에 대한 문제였습니다.

    그 이유로는,

    1. 중분류 카테고리에는 우리가 흔히 가구를 분류하는 카테고리가 있습니다. 예를 들어 소파, 체어, 테이블 등등 이 있습니다. 그래서 포괄적으로 옵션들을 설정 해줄 수 있었습니다.
    2. 하지만 여기에 옵션을 지정을 해주게 된다면 소분류 카테고리에 있는 1인 소파, 다인용 소파 등 소 카테고리로 분류된 옵션들을 또 만들어 주어야 한다는 문제가 발생 하게 됩니다.
    3. 소분류 카테고리에 옵션을 붙혀준다면, 1인 소파, 다인용 소파에 붙는 옵션들은 소파에 대한 옵션이 비슷하므로, 똑같은 옵션을 붙혀준다는 상황이 발생하였습니다.

    회의를 통해 중분류 카테고리에 옵션 테이블을 붙힐 경우 더욱 상세하게 옵션을 설정 해주어야 하고, 소분류 카테고리의 중복이 된다는 문제점이 더 크다 라는 결론을 내려 소분류 카테고리에 옵션 테이블을 붙히게 되었습니다.

  2. 판매글 테이블에 option column 만들기

    판매글을 등록을 할 때 option table을 저장하기 위한 column을 만들어야 했습니다. 해당 컬럼은 jsonb 형태의 컬럼으로 만들었습니다. 그래서 key 값은 option의 pk값으로, value 값은 option의 name으로 지정하였습니다.

문제 상황

filtering을 구현하기 위해 판매글 테이블에 있는 option column을 정제를 한 후, 필요한 데이터들을 join을 하여 filtering을 한 후 보여줘야 하는 상황이었습니다. 하지만 이렇게 될 경우, 하나의 query문으로 작성을 하기엔 가독성이 안좋아 질 뿐더러, 조회 api가 너무나 느려지는 상황이었습니다.

다음은 하나의 query문으로 작성을 했을 때의 query 성능 입니다.

문제 해결

  1. 옵션 데이터 정제

    판매글 테이블에 option이라는 column을 jsonb 형태로 만든 후 정제를 해야하는 상황인데, key 값을 pk값으로 지정을 하고 value 값을 option 이름으로 지정한 상태라 어떠한 옵션인지를 모르는 상황이었습니다. 예를 들어 이러한 형식으로 되어져 있습니다.

    {"1" : ['플라스틱'], "2" : ["블랙"], "22" : "다리 있음"}
    

    그래서 key의 pk 값을 option 테이블의 pk값과 매치를 시켜 따로 임시 컬럼을 만들어 줘야 하는 상황이었습니다.

    만약 이 정제가 안된다면, 판매글 테이블의 option column을 jsonb 형태로 만들지 않고, option들을 하나씩 컬럼을 만들어야 한다는 생각을 했습니다.

    제가 원했던 형태는 key값이 컬럼으로 보내져, 컬럼의 이름을 지정해줄 수 있게끔 하는 것이 목표였습니다.

    그래서 postgresql의 공식문서를 살펴 보던 중, jsonb_to_record 라는 메소드를 찾아냈습니다. 이 메소드를 사용 하여,

    이러한 형태로 변환을 해줄 수 있었습니다.

  2. materialized view table과 view table

    조회 api가 너무 느려지는 것을 확인 하자 뭔가 다른 방법이 없을까 라는 생각을 했습니다. 그 때 사수가 view 테이블을 만들어 보는게 어떠냐고 했습니다. view table 이라는 것을 모르고 있어서 찾아보았더니, 물리적으로 저장되어져 있는 테이블이 아닌 임시 가상 테이블 이라는 개념이었습니다.

    처음에는 데이터 정제를 하고, 필요한 table을 join 하는 쿼리문을 view table에 저장을 해놓으면 되겠다 생각을 했지만, view table 또한 해당 쿼리문을 매번 실행하는 문제가 있었습니다. 가독성은 좋아지겠지만, 성능에는 큰 차이가 없을 것 같다는 생각이 들었습니다.

    그래서 사수와 함께 이 문제를 어떻게 해결할까를 찾아봤습니다. 이때 발견한 것이 materailized view table 이었습니다. materialized view table은 뷰(View)와 달리 실제 데이터를 저장하는 테이블로, 쿼리 결과를 저장하여 필요할 때마다 캐시로부터 빠르게 데이터를 가져올 수 있는 테이블 이었습니다. 하지만 판매글이 등록이 되거나 업데이트가 될때마다 수동적으로 변환을 시켜주어야 하는 문제가 있었습니다.

    사수와 이야기를 했을 때, 판매글을 조회가 느려지는 것 보단 판매글 등록, 삭제, 업데이트 하는 것이 느려지는게 괜찮다라는 의견을 주어서 materialized view table를 만드는 것으로 결정을 하였습니다.

    그래서 판매글이 생성, 삭제, 업데이트가 될 때마다 materialized view table을 refresh를 시켜주는 trigger를 생성을 해주어 수동적으로 변환을 시켜주었습니다.

    데이터 정제를 하는 쿼리는 materialized view table에, 이 materialized view table에 필요한 테이블을 join 하는 것은 view table을 만들어 주었습니다.

  3. 성능 조회

    materialized view table과 view table을 생성을 하였더니 약 67초 에서 0.08초로 약 67초 가 단축이 된 것을 확인 할 수 있었습니다.

  • 문제를 해결 한 후 생각과 배운점

사실 이 문제를 혼자 해결한다고 했다면 절대 해결할 수 없었을 것 같습니다. DB의 쿼리 성능이라든지, view table, materialized view table 라는 개념들을 이 문제를 해결하면서 처음으로 접하고 배운 것들 이었기 때문입니다. 백엔드 개발자로써 DB를 많이 공부해야 하는데, 그 동안 필요한 기능 개발을 핑계로 공부를 못했었습니다. 하지만 이번의 일을 통해서 DB에 대해 관심이 많아졌고, 아직 부족한 점이 많구나 라는 생각을 했습니다.

이번 일로 배운 점은

  1. 내가 해결하지 못하는 문제를 혼자 짊어지지 말고 사수에게 혹은 다른 팀원들에게 이야기 하기

    혼자 해결하지 못하는 문제를 혼자 짊어지고 있다면, 개발 생산성에 영향을 끼치는 것을 느꼈습니다. 당시 프론트 엔드 분과 같이 협업을 하고 있는 상황이었는데, 옵션 데이터를 정제를 하는데 시간이 오래 걸려 기다리고 있는 상황이었습니다. 그래서 빠르게 사수에게 도움을 요청을 하고 문제를 해결 할 수 있게끔 하는 것이 생산성 저해를 막아준다고 생각을 했습니다.

  2. 테이블에도 실제 테이블이 있고, 가상 테이블이 있다

    view table을 처음 접했을 때, table이라는 용어가 붙혀있으니 내가 아는 table과 같이 물리적으로 실제 저장이 되는 table인줄 알았으나 그게 아니었다. 임시적으로 가상 table이라는 것을 알았다. 마치 with절과 비슷한 개념을 갖고 있다는 것을 알았다.

  3. 무엇이 중요한지 생각해보기

    materialized view table을 만들자고 이야기를 했을 때, 생성, 삭제, 업데이트 하는 부분에서의 속도는 저하가 되지만, 조회하는데 있어서는 속도가 빨라지는게 좋다는 의견이 있었습니다. 물론 모든 부분에서 속도가 빠르다면 더 좋습니다. 하지만 우리의 기술적인 한계가 있었을 때, 무엇이 중요한지 생각을 해봐야 합니다. 우리는 조회 속도는 빨라야 한다 라는 점이 중요하다는 것을 인지를 했기 때문에, 기능 개선하는데 시간을 단축 시킬 수 있었다고 생각합니다.

또한 postgresql 공식문서를 살펴보며 여러가지 메소드들을 확인하면서 사용해볼 수 있는 좋은 경험을 할 수 있었습니다. 그리고 explain을 사용하여 쿼리 실행 계획을 보는 방법을 익힐 수 있었습니다. 이번 일 계기로 DB에 조금 더 관심이 생겼고, 집중적으로 공부를 해보고 싶다는 생각이 들었습니다.

댓글남기기