InfoGrab DocsInfoGrab Docs

데이터베이스 리뷰 가이드라인

요약

이 페이지는 데이터베이스 리뷰에 대한 내용입니다. 다음 경우에는 데이터베이스 리뷰가 필요합니다. 데이터베이스 리뷰어는 변경 사항에서 지나치게 복잡한 쿼리를 찾아내 더 꼼꼼히 검토해야 합니다. ~database 리뷰를 요청할 때는 다음 산출물을 제공해야 합니다.

이 페이지는 데이터베이스 리뷰에 대한 내용입니다. 코드 리뷰 전반에 대한 더 폭넓은 조언과 모범 사례는 코드 리뷰 가이드를 참고합니다.

일반 프로세스#

다음 경우에는 데이터베이스 리뷰가 필요합니다.

  • 데이터베이스 스키마를 건드리거나 데이터 마이그레이션을 수행하는 변경. 다음 위치의 파일이 여기에 해당합니다.
    • db/
    • lib/gitlab/background_migration/
  • 데이터베이스 도구 변경. 예를 들면 다음과 같습니다.
    • lib/gitlab/database/의 마이그레이션 또는 ActiveRecord 헬퍼
    • 로드 밸런싱
  • 단순하지 않은 SQL 쿼리를 생성하는 변경. 복잡한 쿼리가 도입되는지, 그리고 데이터베이스 리뷰가 필요한지는 일반적으로 머지 리퀘스트 작성자가 판단합니다.
  • count, distinct_count, estimate_batch_distinct_count, sum을 사용하는 Service Data 메트릭 변경. 이러한 메트릭은 큰 테이블에 대해 복잡한 쿼리를 수행할 수 있습니다. 구현 상세는 Analytics Instrumentation Guide를 참고합니다.
  • ActiveRecord 객체에 update, upsert, delete, update_all, upsert_all, delete_all, destroy_all 메서드를 사용하는 변경.

데이터베이스 리뷰어는 변경 사항에서 지나치게 복잡한 쿼리를 찾아내 더 꼼꼼히 검토해야 합니다. 작성자가 검토할 쿼리를 따로 지목하지 않았고 지나치게 복잡한 쿼리도 없다면, 마이그레이션만 검토하는 것으로 충분합니다.

필수 항목#

~database 리뷰를 요청할 때는 다음 산출물을 제공해야 합니다. 머지 리퀘스트 설명에 이 항목이 없으면 리뷰는 작성자에게 다시 배정됩니다.

마이그레이션#

새 마이그레이션이 도입되면 데이터베이스 리뷰어는 모든 마이그레이션에 대해 마이그레이션 실행(db:migrate)과 롤백(db:rollback) 결과를 모두 검토해야 합니다.

GitLab에는 이 결과를 CI job 로그에 남기는 자동화 도구가 있습니다(db:check-migrations 파이프라인 job 이 제공합니다). 작성자가 이 결과를 머지 리퀘스트 설명에 넣을 필요는 없지만, 넣어 두면 리뷰어에게 도움이 됩니다. 이 봇은 마이그레이션이 올바르게 되돌려지는지도 확인합니다.

쿼리#

새 쿼리를 도입했거나 기존 쿼리를 변경했다면 다음을 제공해야 합니다.

  • 머지 리퀘스트에 포함된 각 원시 SQL 쿼리에 대한 쿼리 플랜. 각 원시 SQL 조각 뒤에 쿼리 플랜 링크를 함께 넣습니다.
  • 변경했거나 추가한 모든 쿼리의 원시 SQL(ActiveRecord 쿼리에서 변환한 것).
    • 기존 쿼리를 변경하는 경우에는 이전 버전과 새 버전 쿼리의 원시 SQL을 각각의 쿼리 플랜과 함께 제공해야 합니다.

이 정보를 제공하는 방법은 쿼리 추가 또는 수정 시 준비 사항을 참고합니다.

역할 및 프로세스#

머지 리퀘스트 작성자의 역할은 다음과 같습니다.

데이터베이스 리뷰어의 역할은 다음과 같습니다.

  • 필수 산출물이 올바른 형식으로 제공되었는지 확인합니다. 그렇지 않으면 머지 리퀘스트를 작성자에게 다시 배정합니다.
  • MR을 1차로 검토하고 작성자에게 개선안을 제안합니다.
  • 검토가 끝나면 MR에 ~"database::reviewed" 레이블을 다시 지정하고 승인한 뒤, Reviewer Roulette 이 제안한 데이터베이스 메인테이너에게 리뷰를 요청합니다.

데이터베이스 메인테이너의 역할은 다음과 같습니다.

  • MR에 대한 최종 데이터베이스 리뷰를 수행합니다.
  • 추가 개선 사항이나 관련 변경 사항을 데이터베이스 리뷰어 및 MR 작성자와 논의합니다.
  • 마지막으로 MR을 승인하고 ~"database::approved" 레이블을 다시 지정합니다
  • 대기 중인 다른 승인이 없으면 MR을 머지하고, 필요하면 다른 메인테이너(프론트엔드, 백엔드, 문서)에게 넘깁니다.

리뷰 작업 분배#

리뷰 작업은 reviewer roulette로 분배합니다 (예시). MR 작성자는 제안된 데이터베이스 리뷰어에게 리뷰를 요청합니다. 리뷰어가 승인하면 제안된 데이터베이스 메인테이너에게 넘깁니다.

reviewer roulette 이 데이터베이스 리뷰어와 메인테이너를 제안하지 않았다면, ~database 레이블을 적용했는지 확인하고 danger-review CI job을 다시 실행하거나, @gl-database 팀에서 직접 선택합니다.

데이터베이스 리뷰를 위한 머지 리퀘스트 준비 방법#

리뷰를 더 쉽고 빠르게 진행할 수 있도록 다음 준비 사항을 고려합니다.

마이그레이션 추가 시 준비 사항#

  • 문서에 따라 db/structure.sql 이 업데이트되었는지 확인하고, 추가로 db/schema_migrations 아래의 관련 버전 파일이 추가·제거되었는지도 확인합니다.
  • 문서에 따라 Database Dictionary가 업데이트되었는지 확인합니다.
  • change 메서드를 사용하거나 up을 사용할 때 down 메서드를 포함해 마이그레이션을 되돌릴 수 있게 만듭니다.
    • 롤백 절차를 포함하거나 변경을 롤백하는 방법을 설명합니다.
  • db:check-migrations 파이프라인 job 이 성공했고 마이그레이션 롤백이 예상대로 동작하는지 확인합니다.
    • db:check-schema job 이 성공했고 롤백에서 예상치 못한 스키마 변경이 생기지 않았는지 확인합니다. 스키마가 변경된 경우 이 job은 경고만 표시할 수도 있습니다.
    • 리뷰 과정에서 마이그레이션을 수정할 때마다 위 job 들이 계속 성공하는지 확인합니다.
  • 필요하다면 spec/migrations에 마이그레이션 테스트를 추가합니다. 자세한 내용은 GitLab의 Rails 마이그레이션 테스트를 참고합니다.
  • 잠금 재시도는 모든 트랜잭션 마이그레이션에서 기본으로 활성화되어 있습니다. 비트랜잭션 마이그레이션의 사용 사례와 해결 방법은 관련 문서를 참고합니다.
  • 타당한 이유가 없는 한 RuboCop 검사를 비활성화하지 않습니다.
  • 큰 테이블에 인덱스를 추가할 때는 Database Lab에서 CREATE INDEX CONCURRENTLY로 실행을 테스트하고 실행 시간을 MR 설명에 적습니다.
    • 실행 시간은 Database Lab과 GitLab.com 사이에 큰 차이가 있지만, Database Lab의 실행 시간이 높다면 GitLab.com 에서의 실행 시간도 상당히 길다는 신호일 수 있습니다.
    • Database Lab 에서의 실행 시간이 10분을 넘으면 인덱스를 사후 마이그레이션으로 옮겨야 합니다. 이 경우 인덱스를 사용하는 코드가 배포될 때 인덱스가 준비되어 있도록 마이그레이션과 애플리케이션 변경을 별도의 릴리스로 나눠야 할 수 있습니다.
  • test 스테이지의 데이터베이스 테스트 job(db:gitlabcom-database-testing)을 수동으로 트리거합니다.
    • 이 job은 Database Lab 클론에서 마이그레이션을 실행하고 결과(쿼리, 실행 시간, 크기 변화)를 MR에 남깁니다.
    • 마이그레이션 실행 시간과 경고를 검토합니다.

데이터 마이그레이션 추가 시 준비 사항#

데이터 마이그레이션은 본질적으로 위험합니다. 운영 데이터가 손상되거나 유실되는 오류 가능성을 줄이기 위해 추가 조치가 필요합니다.

MR 설명에 다음을 포함합니다.

  • 마이그레이션 자체를 되돌릴 수 없다면, 인시던트가 발생했을 때 데이터 변경을 어떻게 되돌릴 수 있는지에 대한 상세 내용. 예를 들어 레코드를 삭제하는 마이그레이션(대부분 자동으로 되돌릴 수 없는 작업)이라면 삭제된 레코드를 어떻게 복구할 수 있는지 설명합니다.
  • 마이그레이션이 데이터를 삭제한다면 ~data-deletion 레이블을 적용합니다.
  • 오류 발생 시 사용자 경험에 미칠 영향에 대한 간결한 설명. 예를 들면 "에픽에서 이슈가 갑자기 사라짐" 같은 내용입니다.
  • 쿼리가 의도대로 동작함을 보여 주는 쿼리 플랜의 관련 데이터. 예를 들어 수정되거나 삭제되는 레코드의 대략적인 수가 있습니다.

쿼리 추가 또는 수정 시 준비 사항#

원시 SQL#
  • MR 설명에 원시 SQL을 적습니다. pgFormatter나 https://paste.depesz.com로 보기 좋게 정리하고, 일반 따옴표(예를 들어 "projects"."id")를 사용하며 스마트 따옴표(예를 들어 “projects”.“id”)는 피하는 것이 좋습니다.

  • 파라미터에 따라 동적으로 생성되는 쿼리라면 변형마다 원시 SQL을 하나씩 제공해야 합니다.

    예를 들어 프로젝트에 대한 선택적 필터를 파라미터로 받을 수 있는 이슈 finder 라면, 이슈만 조회하는 쿼리와 이슈와 프로젝트를 조인해 필터를 적용하는 쿼리를 모두 포함해야 합니다.

    finder 나 그 밖의 메서드 중에는 매우 많은 조합을 생성하는 것도 있습니다. 생성 가능한 모든 쿼리를 빠짐없이 넣을 필요는 없고, 모든 파라미터를 포함한 쿼리 하나와 생성되는 쿼리 유형마다 하나씩만 있으면 됩니다.

    예를 들어 조인이나 group by 절이 선택 사항이라면, group by 절이 없는 버전과 조인이 더 적은 버전도 포함하되 나머지 테이블에 대한 적절한 필터는 유지합니다.

  • 쿼리가 항상 limit과 offset과 함께 사용된다면, 허용되는 최댓값 limit과 0이 아닌 offset을 항상 함께 포함합니다.

애플리케이션이 실행하는 SQL을 찾는 팁

쿼리를 검토할 때는 스코프, 페이지네이션, limit을 포함해 데이터베이스에서 실제로 실행되는 SQL 쿼리를 평가해야 합니다. Rails 코드만 읽고 정확한 쿼리를 추론하기는 어렵거나 때로는 불가능합니다. 가장 정확한 SQL을 얻으려면 다음 방법 중 하나를 사용해 봅니다.

  1. performance bar 사용: 기능을 직접 테스트한 뒤 performance bar의 pg 영역을 선택하면 실행된 SQL 쿼리를 확인할 수 있습니다. API 요청의 쿼리를 보려면 오른쪽 드롭다운 메뉴에서 해당 요청을 찾아 선택합니다.

  2. development.log 확인: 기능을 테스트한 다음 GitLab 디렉터리의 log/development.log 를 열어 애플리케이션이 실행한 모든 쿼리를 확인합니다. 여기에는 Sidekiq 워커에서 실행된 쿼리는 포함되지 않습니다.

  3. ActiveRecord::Base.logger로 스펙 실행: RSpec 테스트에 다음 블록을 추가하면 쿼리를 stdout으로 출력할 수 있습니다.

    before do
      ActiveRecord::Base.logger = Logger.new($stdout)
    end
    
    after do
      ActiveRecord::Base.logger = nil
    end
    

    bundle exec rspec <test_file>로 테스트를 실행하면 쿼리가 테스트 출력에 나타납니다. 이 방법은 통합 테스트에서만 올바른 쿼리를 보여 줍니다. 페이지네이션 미들웨어처럼 ActiveRecord 관계를 수정하는 구성 요소가 더 있으면 단위 테스트의 출력은 정확하지 않을 수 있습니다.

쿼리 플랜#
  • 머지 리퀘스트에 포함된 각 원시 SQL 쿼리에 대한 쿼리 플랜. 각 원시 SQL 조각 뒤에 쿼리 플랜 링크를 함께 넣습니다.
  • postgres.ai 챗봇에서 explain 명령으로 생성한 플랜의 링크를 제공합니다. explain 명령은 EXPLAIN ANALYZE를 실행합니다.
    • Database Lab에서 정확한 결과를 얻을 수 없다면 개발 환경에 데이터를 시드한 뒤 EXPLAIN ANALYZE의 출력을 대신 제공해야 할 수 있습니다. 플랜 링크는 explain.depesz.com이나 explain.dalibo.com으로 만듭니다. 이때 양식에 플랜과 사용한 쿼리를 모두 붙여 넣습니다.
  • 쿼리 플랜을 제공할 때는 충분한 데이터가 조회되는지 확인합니다.
    • 충분한 데이터로 쿼리 플랜을 만들려면 다음 ID를 사용할 수 있습니다.

      • 그룹이 관련된 쿼리에는 gitlab-org 네임스페이스(namespace_id = 9970).
      • 프로젝트가 관련된 쿼리에는 gitlab-org/gitlab-foss(project_id = 13083) 또는 gitlab-org/gitlab(project_id = 278964) 프로젝트.
        • 프로젝트 멤버십이 관련된 쿼리에서는 쿼리 플랜을 만들기 위해 이 프로젝트들의 project_namespace_id가 필요할 수 있습니다. 값은 15846663(gitlab-org/gitlab)과 15846626(gitlab-org/gitlab-foss)입니다
      • 사용자가 관련된 쿼리에는 gitlab-qa 사용자(user_id = 1614863).
        • 필요하다면 본인의 user_id 나, 쿼리 플랜을 만드는 데 사용하는 프로젝트·그룹에서 이력이 긴 사용자의 user_id를 사용할 수도 있습니다.
    • 즉 어떤 쿼리 플랜도 0건을 반환하거나 (limit 이 있는 경우) 지정한 limit보다 적은 건수를 반환해서는 안 됩니다. 배치 처리에 사용되는 쿼리라면 결과가 충분히 포함된 적절한 예시 배치를 찾아 제공해야 합니다.

      [!note] UPDATE 문은 항상 0건을 반환합니다. 어떤 행이 업데이트되는지 확인하려면 아래 줄들을 살펴봐야 합니다.

      예를 들어 UPDATE 문은 0건을 반환하지만, -> Index scan으로 시작하는 줄에서 1행을 업데이트한다는 것을 확인할 수 있습니다.

      EXPLAIN UPDATE p_ci_pipelines SET updated_at = current_timestamp WHERE id = 1606117348;
      
       ModifyTable on public.p_ci_pipelines  (cost=0.58..3.60 rows=0 width=0) (actual time=5.977..5.978 rows=0 loops=1)
        Buffers: shared hit=339 read=4 dirtied=4
        WAL: records=20 fpi=4 bytes=21800
        I/O Timings: read=4.920 write=0.000
        ->  Index Scan using ci_pipelines_pkey on public.ci_pipelines p_ci_pipelines_1  (cost=0.58..3.60 rows=1 width=18) (actual time=0.041..0.044 rows=1 loops=1)
              Index Cond: (p_ci_pipelines_1.id = 1606117348)
              Buffers: shared hit=8
              I/O Timings: read=0.000 write=0.000
      
    • 쿼리가 GitLab.com의 새 기능에 속해서 프로덕션에서 데이터를 반환하지 않는 경우에는 다음과 같이 합니다.

      • 쿼리를 분석해 로컬 환경의 플랜을 제공할 수 있습니다.
      • postgres.ai에서는 데이터 업데이트(exec UPDATE issues SET ...)와 새 테이블·칼럼 생성(exec ALTER TABLE issues ADD COLUMN ...)이 가능합니다.
    • 실제 반환 레코드 수를 확인하는 방법은 EXPLAIN 플랜 이해하기에서 자세히 다룹니다

  • 쿼리를 변경하는 경우에는 변경 전후의 SQL 쿼리와 플랜을 모두 제공하는 것이 좋습니다. 그래야 차이를 빠르게 확인할 수 있습니다.
  • 성능 개선을 보여 주는 데이터를 포함하되, 가급적 벤치마크 형태로 제공합니다.
  • 쿼리 플랜을 평가할 때는 데이터베이스에 대해 실제로 실행되는 최종 쿼리가 필요합니다. finder 나 스코프에서 ActiveRecord::Relation으로 반환되는 중간 쿼리는 분석할 필요가 없습니다. PostgreSQL 쿼리 플랜은 limit을 비롯해 최종 실행 전에 추가될 수 있는 모든 최종 파라미터에 좌우됩니다. 실제로 실행된 쿼리를 확실히 확인하는 한 가지 방법은 log/development.log를 보는 것입니다.

기존 테이블에 외래 키 추가 시 준비 사항#

  • 외래 키를 추가하기 전에 소스 테이블의 고아 행을 제거하는 마이그레이션을 포함합니다.
  • 더 이상 필요하지 않게 된 dependent: ...는 모두 제거합니다.

테이블 추가 시 준비 사항#

  • 테이블 칼럼 정렬 가이드라인에 따라 칼럼을 정렬합니다.
  • 다른 테이블의 데이터를 가리키는 칼럼에는 인덱스를 포함해 외래 키를 추가합니다.
  • WHERE, ORDER BY, GROUP BY, JOIN 같은 구문에 사용되는 필드에는 인덱스를 추가합니다.
  • 새 테이블은 db/fixtures/development/의 파일로 시드해야 합니다. 이 픽스처는 업그레이드가 정상적으로 완료되는지 확인하는 데도 사용되므로, 새 테이블에는 항상 데이터가 채워져야 합니다. 머지 리퀘스트로 추가된 테이블이 시드 후에도 비어 있으면 run-dev-fixtures-ee job 이 실패합니다.
  • 정적 데이터를 저장하는 데 데이터베이스 테이블을 사용하지 않도록 합니다. 대신 fixed items model을 사용합니다.
  • 새 테이블과 칼럼이 반드시 위험한 것은 아니지만, 시간이 지나면 일부 접근 패턴은 본질적으로 확장하기 어려워집니다. 이런 위험한 패턴을 미리 찾아내려면 접근 방식과 규모에 대한 예상을 문서로 남겨야 합니다. MR 설명에 다음 항목에 대한 답을 포함합니다.
    • 향후 3개월, 6개월, 1년 동안 새 테이블의 예상 증가량과 그 예상의 근거가 되는 가정
    • 3개월, 6개월, 1년 뒤 이 테이블의 시간당 예상 읽기·쓰기 횟수, 행이 업데이트되는 상황, 그리고 그 예상의 근거가 되는 가정
    • 예상 데이터 규모와 접근 패턴을 고려할 때 새 테이블이 GitLab.com 이나 GitLab Self-Managed 인스턴스의 가용성에 위험이 되는지, 제안한 설계가 GitLab.com과 GitLab Self-Managed 고객의 요구를 감당할 만큼 확장되는지

칼럼, 테이블, 인덱스 또는 기타 구조 제거 시 준비 사항#

  • 칼럼 삭제 가이드라인을 따릅니다.
  • 일반적으로 인덱스와 외래 키는 사후 배포 마이그레이션에서 제거하는 것이 모범 사례입니다(엄격한 규칙은 아닙니다).
    • 작은 테이블의 인덱스와 외래 키 제거는 예외입니다.
  • 인덱스를 삭제할 때는 복합 인덱스 칼럼 순서 요건을 확인해 복합 인덱스가 대체 역할을 할 수 있는지 검증합니다.
  • 복합 인덱스를 추가하면 다른 인덱스가 불필요해질 수 있으므로, 같은 마이그레이션에서 그 인덱스를 제거합니다. 예를 들어 index(column_A, column_B, column_C)를 추가하면 index(column_A, column_B)와 index(column_A) 인덱스가 불필요해집니다.

대량 업데이트 작업 사용 시 준비 사항#

ActiveRecord의 update, upsert, delete, update_all, upsert_all, delete_all, destroy_all 메서드는 데이터를 수정하고 성능이 나쁠 수 있으며, 스코프를 잘못 지정하면 데이터를 파괴할 수도 있으므로 각별히 주의해야 합니다. 이 메서드들은 공통 테이블 표현식(CTE) 구문과도 호환되지 않습니다. 이 메서드를 사용하면 Danger가 머지 리퀘스트 diff에 코멘트를 남깁니다.

쿼리 추가 또는 수정 시 준비 사항 문서에 따라 원시 SQL 쿼리와 쿼리 플랜을 머지 리퀘스트 설명에 추가하고 데이터베이스 리뷰를 요청합니다.

유용한 팁#

  • 특정 브랜치에서 마이그레이션을 적용하고 되돌리는 일이 잦다면 scripts/database/migrate.rb 를 사용해 이 과정을 더 효율적으로 처리할 수 있습니다.

데이터베이스 리뷰 방법#

기본 마이그레이션 요구 사항#

  • 데이터베이스 테스트 job(db:gitlabcom-database-testing)이 통과하는지 확인합니다.
  • db/structure.sql에 이 머지 리퀘스트의 마이그레이션과 관련된 변경만 있고 무관한 스키마 수정은 없는지 확인합니다
  • 마이그레이션을 되돌릴 수 있는지 확인하고 #down 메서드를 구현했는지 확인합니다
  • 마이그레이션이 트랜잭션 안에서 실행되거나(Rails 기본값), disable_ddl_transaction!과 함께 동시성 작업만 사용하는지 확인합니다
  • db/schema_migrations 아래의 관련 버전 파일이 추가·제거되었는지 확인합니다

스타일 및 표준 준수#

대규모 테이블 및 크기 제한#

  • 크기 임계값을 넘은 기존 테이블에 인덱스와 칼럼이 추가되지 않았는지 확인합니다. 필요하다면 작성자는 데이터베이스 프레임워크 팀에 예외 요청을 제출할 수 있습니다
  • 큰 테이블에 인덱스를 추가했고 Database Lab에서 실행 시간이 길었다면(1시간 초과) 다음과 같이 처리합니다.
    • 비동기로 추가하는 절차를 따릅니다
    • 메인테이너: 머지 리퀘스트가 머지된 뒤 #f_upcoming_release Slack 채널에서 릴리스 매니저에게 알립니다

타이밍 및 성능 표준#

  • 마이그레이션 타이밍 가이드라인을 확인합니다
  • 쿼리 실행 시간을 확인합니다(해당되는 경우). 단일 트랜잭션에서 마이그레이션이 실행하는 누적 쿼리 시간은 GitLab.com 기준 15초 안에 충분히 들어와야 하며, 그보다 훨씬 짧을수록 좋습니다
  • 일반적인 지침은 쿼리 실행 시간을 100ms 이하로 유지하는 것입니다

마이그레이션 배치 및 타이밍#

  • GitLab.com 에서의 실행 시간을 예상합니다
  • 적절한 마이그레이션 유형을 선택합니다
  • 데이터 마이그레이션은 되돌릴 수 있어야 하며, 그렇지 않다면 왜 아무 동작도 하지 않거나 되돌릴 수 없는지 주석으로 남겨야 합니다. 이는 모든 유형의 마이그레이션(일반, 사후 배포, 백그라운드 마이그레이션)에 적용됩니다

백그라운드 마이그레이션 세부 사항#

  • 배치 백그라운드 마이그레이션을 확인합니다
  • gitlab-com-database-testing 코멘트(Database Migrations (on the main database) 등의 제목)에 제공된 예상 시간이 쿼리 성능 가이드라인에 부합하는지 확인합니다
  • 백그라운드 마이그레이션은 보통 다음 용도로 사용되며, 이에 국한되지는 않습니다.
    • 큰 테이블의 데이터 마이그레이션
    • 데이터셋의 레코드마다 여러 SQL 쿼리를 수행하는 작업
  • 쿼리를 검토합니다(예를 들어 배치 크기가 적절한지 확인합니다)
  • 위 마이그레이션 배치 및 타이밍 절의 배치 가이드라인을 따릅니다

새 테이블 및 칼럼 리뷰#

  • 관계형 모델링과 설계 선택을 검토합니다
  • 명시된 접근 패턴과 데이터 양이 타당한지, 그 근거가 되는 가정이 합리적인지, 이러한 패턴이 안정성에 위험을 주는지 확인합니다
  • 칼럼이 공간을 절약하도록 정렬되었는지 확인합니다
  • 다른 테이블을 참조하는 외래 키가 있는지 확인합니다
  • 칼럼을 제거하는 경우 해당 칼럼이 이전 릴리스에서 무시 처리되었는지 확인합니다

쿼리 성능 분석#

  • 지나치게 복잡한 쿼리와 작성자가 검토를 요청한 쿼리가 있는지 확인합니다(해당되는 경우)
  • 새로 추가하거나 수정한 모든 쿼리에 대해 SQL 문과 Database Lab 쿼리 플랜이 머지 리퀘스트 설명에 모두 포함되어 있는지 확인합니다
  • 해당 쿼리에서 데이터 분포와 관련된 파라미터를 검토합니다
  • 쿼리 플랜을 확인하고 필요한 개선안을 제안합니다(예를 들어 쿼리 구조 변경, 인덱스 추가·제거 등). 미해결 질문이 있으면 #database_maintainers 채널에 문의합니다.
  • N+1 문제를 피하고 쿼리 수를 최소화합니다

데이터베이스 리뷰 가이드라인

GitLab v19.4
원문 보기

요약

이 페이지는 데이터베이스 리뷰에 대한 내용입니다. 다음 경우에는 데이터베이스 리뷰가 필요합니다. 데이터베이스 리뷰어는 변경 사항에서 지나치게 복잡한 쿼리를 찾아내 더 꼼꼼히 검토해야 합니다. ~database 리뷰를 요청할 때는 다음 산출물을 제공해야 합니다.

이 페이지는 데이터베이스 리뷰에 대한 내용입니다. 코드 리뷰 전반에 대한 더 폭넓은 조언과 모범 사례는 코드 리뷰 가이드를 참고합니다.

일반 프로세스#

다음 경우에는 데이터베이스 리뷰가 필요합니다.

  • 데이터베이스 스키마를 건드리거나 데이터 마이그레이션을 수행하는 변경. 다음 위치의 파일이 여기에 해당합니다.
    • db/
    • lib/gitlab/background_migration/
  • 데이터베이스 도구 변경. 예를 들면 다음과 같습니다.
    • lib/gitlab/database/의 마이그레이션 또는 ActiveRecord 헬퍼
    • 로드 밸런싱
  • 단순하지 않은 SQL 쿼리를 생성하는 변경. 복잡한 쿼리가 도입되는지, 그리고 데이터베이스 리뷰가 필요한지는 일반적으로 머지 리퀘스트 작성자가 판단합니다.
  • count, distinct_count, estimate_batch_distinct_count, sum을 사용하는 Service Data 메트릭 변경. 이러한 메트릭은 큰 테이블에 대해 복잡한 쿼리를 수행할 수 있습니다. 구현 상세는 Analytics Instrumentation Guide를 참고합니다.
  • ActiveRecord 객체에 update, upsert, delete, update_all, upsert_all, delete_all, destroy_all 메서드를 사용하는 변경.

데이터베이스 리뷰어는 변경 사항에서 지나치게 복잡한 쿼리를 찾아내 더 꼼꼼히 검토해야 합니다. 작성자가 검토할 쿼리를 따로 지목하지 않았고 지나치게 복잡한 쿼리도 없다면, 마이그레이션만 검토하는 것으로 충분합니다.

필수 항목#

~database 리뷰를 요청할 때는 다음 산출물을 제공해야 합니다. 머지 리퀘스트 설명에 이 항목이 없으면 리뷰는 작성자에게 다시 배정됩니다.

마이그레이션#

새 마이그레이션이 도입되면 데이터베이스 리뷰어는 모든 마이그레이션에 대해 마이그레이션 실행(db:migrate)과 롤백(db:rollback) 결과를 모두 검토해야 합니다.

GitLab에는 이 결과를 CI job 로그에 남기는 자동화 도구가 있습니다(db:check-migrations 파이프라인 job 이 제공합니다). 작성자가 이 결과를 머지 리퀘스트 설명에 넣을 필요는 없지만, 넣어 두면 리뷰어에게 도움이 됩니다. 이 봇은 마이그레이션이 올바르게 되돌려지는지도 확인합니다.

쿼리#

새 쿼리를 도입했거나 기존 쿼리를 변경했다면 다음을 제공해야 합니다.

  • 머지 리퀘스트에 포함된 각 원시 SQL 쿼리에 대한 쿼리 플랜. 각 원시 SQL 조각 뒤에 쿼리 플랜 링크를 함께 넣습니다.
  • 변경했거나 추가한 모든 쿼리의 원시 SQL(ActiveRecord 쿼리에서 변환한 것).
    • 기존 쿼리를 변경하는 경우에는 이전 버전과 새 버전 쿼리의 원시 SQL을 각각의 쿼리 플랜과 함께 제공해야 합니다.

이 정보를 제공하는 방법은 쿼리 추가 또는 수정 시 준비 사항을 참고합니다.

역할 및 프로세스#

머지 리퀘스트 작성자의 역할은 다음과 같습니다.

데이터베이스 리뷰어의 역할은 다음과 같습니다.

  • 필수 산출물이 올바른 형식으로 제공되었는지 확인합니다. 그렇지 않으면 머지 리퀘스트를 작성자에게 다시 배정합니다.
  • MR을 1차로 검토하고 작성자에게 개선안을 제안합니다.
  • 검토가 끝나면 MR에 ~"database::reviewed" 레이블을 다시 지정하고 승인한 뒤, Reviewer Roulette 이 제안한 데이터베이스 메인테이너에게 리뷰를 요청합니다.

데이터베이스 메인테이너의 역할은 다음과 같습니다.

  • MR에 대한 최종 데이터베이스 리뷰를 수행합니다.
  • 추가 개선 사항이나 관련 변경 사항을 데이터베이스 리뷰어 및 MR 작성자와 논의합니다.
  • 마지막으로 MR을 승인하고 ~"database::approved" 레이블을 다시 지정합니다
  • 대기 중인 다른 승인이 없으면 MR을 머지하고, 필요하면 다른 메인테이너(프론트엔드, 백엔드, 문서)에게 넘깁니다.

리뷰 작업 분배#

리뷰 작업은 reviewer roulette로 분배합니다 (예시). MR 작성자는 제안된 데이터베이스 리뷰어에게 리뷰를 요청합니다. 리뷰어가 승인하면 제안된 데이터베이스 메인테이너에게 넘깁니다.

reviewer roulette 이 데이터베이스 리뷰어와 메인테이너를 제안하지 않았다면, ~database 레이블을 적용했는지 확인하고 danger-review CI job을 다시 실행하거나, @gl-database 팀에서 직접 선택합니다.

데이터베이스 리뷰를 위한 머지 리퀘스트 준비 방법#

리뷰를 더 쉽고 빠르게 진행할 수 있도록 다음 준비 사항을 고려합니다.

마이그레이션 추가 시 준비 사항#

  • 문서에 따라 db/structure.sql 이 업데이트되었는지 확인하고, 추가로 db/schema_migrations 아래의 관련 버전 파일이 추가·제거되었는지도 확인합니다.
  • 문서에 따라 Database Dictionary가 업데이트되었는지 확인합니다.
  • change 메서드를 사용하거나 up을 사용할 때 down 메서드를 포함해 마이그레이션을 되돌릴 수 있게 만듭니다.
    • 롤백 절차를 포함하거나 변경을 롤백하는 방법을 설명합니다.
  • db:check-migrations 파이프라인 job 이 성공했고 마이그레이션 롤백이 예상대로 동작하는지 확인합니다.
    • db:check-schema job 이 성공했고 롤백에서 예상치 못한 스키마 변경이 생기지 않았는지 확인합니다. 스키마가 변경된 경우 이 job은 경고만 표시할 수도 있습니다.
    • 리뷰 과정에서 마이그레이션을 수정할 때마다 위 job 들이 계속 성공하는지 확인합니다.
  • 필요하다면 spec/migrations에 마이그레이션 테스트를 추가합니다. 자세한 내용은 GitLab의 Rails 마이그레이션 테스트를 참고합니다.
  • 잠금 재시도는 모든 트랜잭션 마이그레이션에서 기본으로 활성화되어 있습니다. 비트랜잭션 마이그레이션의 사용 사례와 해결 방법은 관련 문서를 참고합니다.
  • 타당한 이유가 없는 한 RuboCop 검사를 비활성화하지 않습니다.
  • 큰 테이블에 인덱스를 추가할 때는 Database Lab에서 CREATE INDEX CONCURRENTLY로 실행을 테스트하고 실행 시간을 MR 설명에 적습니다.
    • 실행 시간은 Database Lab과 GitLab.com 사이에 큰 차이가 있지만, Database Lab의 실행 시간이 높다면 GitLab.com 에서의 실행 시간도 상당히 길다는 신호일 수 있습니다.
    • Database Lab 에서의 실행 시간이 10분을 넘으면 인덱스를 사후 마이그레이션으로 옮겨야 합니다. 이 경우 인덱스를 사용하는 코드가 배포될 때 인덱스가 준비되어 있도록 마이그레이션과 애플리케이션 변경을 별도의 릴리스로 나눠야 할 수 있습니다.
  • test 스테이지의 데이터베이스 테스트 job(db:gitlabcom-database-testing)을 수동으로 트리거합니다.
    • 이 job은 Database Lab 클론에서 마이그레이션을 실행하고 결과(쿼리, 실행 시간, 크기 변화)를 MR에 남깁니다.
    • 마이그레이션 실행 시간과 경고를 검토합니다.

데이터 마이그레이션 추가 시 준비 사항#

데이터 마이그레이션은 본질적으로 위험합니다. 운영 데이터가 손상되거나 유실되는 오류 가능성을 줄이기 위해 추가 조치가 필요합니다.

MR 설명에 다음을 포함합니다.

  • 마이그레이션 자체를 되돌릴 수 없다면, 인시던트가 발생했을 때 데이터 변경을 어떻게 되돌릴 수 있는지에 대한 상세 내용. 예를 들어 레코드를 삭제하는 마이그레이션(대부분 자동으로 되돌릴 수 없는 작업)이라면 삭제된 레코드를 어떻게 복구할 수 있는지 설명합니다.
  • 마이그레이션이 데이터를 삭제한다면 ~data-deletion 레이블을 적용합니다.
  • 오류 발생 시 사용자 경험에 미칠 영향에 대한 간결한 설명. 예를 들면 "에픽에서 이슈가 갑자기 사라짐" 같은 내용입니다.
  • 쿼리가 의도대로 동작함을 보여 주는 쿼리 플랜의 관련 데이터. 예를 들어 수정되거나 삭제되는 레코드의 대략적인 수가 있습니다.

쿼리 추가 또는 수정 시 준비 사항#

원시 SQL#
  • MR 설명에 원시 SQL을 적습니다. pgFormatter나 https://paste.depesz.com로 보기 좋게 정리하고, 일반 따옴표(예를 들어 "projects"."id")를 사용하며 스마트 따옴표(예를 들어 “projects”.“id”)는 피하는 것이 좋습니다.

  • 파라미터에 따라 동적으로 생성되는 쿼리라면 변형마다 원시 SQL을 하나씩 제공해야 합니다.

    예를 들어 프로젝트에 대한 선택적 필터를 파라미터로 받을 수 있는 이슈 finder 라면, 이슈만 조회하는 쿼리와 이슈와 프로젝트를 조인해 필터를 적용하는 쿼리를 모두 포함해야 합니다.

    finder 나 그 밖의 메서드 중에는 매우 많은 조합을 생성하는 것도 있습니다. 생성 가능한 모든 쿼리를 빠짐없이 넣을 필요는 없고, 모든 파라미터를 포함한 쿼리 하나와 생성되는 쿼리 유형마다 하나씩만 있으면 됩니다.

    예를 들어 조인이나 group by 절이 선택 사항이라면, group by 절이 없는 버전과 조인이 더 적은 버전도 포함하되 나머지 테이블에 대한 적절한 필터는 유지합니다.

  • 쿼리가 항상 limit과 offset과 함께 사용된다면, 허용되는 최댓값 limit과 0이 아닌 offset을 항상 함께 포함합니다.

애플리케이션이 실행하는 SQL을 찾는 팁

쿼리를 검토할 때는 스코프, 페이지네이션, limit을 포함해 데이터베이스에서 실제로 실행되는 SQL 쿼리를 평가해야 합니다. Rails 코드만 읽고 정확한 쿼리를 추론하기는 어렵거나 때로는 불가능합니다. 가장 정확한 SQL을 얻으려면 다음 방법 중 하나를 사용해 봅니다.

  1. performance bar 사용: 기능을 직접 테스트한 뒤 performance bar의 pg 영역을 선택하면 실행된 SQL 쿼리를 확인할 수 있습니다. API 요청의 쿼리를 보려면 오른쪽 드롭다운 메뉴에서 해당 요청을 찾아 선택합니다.

  2. development.log 확인: 기능을 테스트한 다음 GitLab 디렉터리의 log/development.log 를 열어 애플리케이션이 실행한 모든 쿼리를 확인합니다. 여기에는 Sidekiq 워커에서 실행된 쿼리는 포함되지 않습니다.

  3. ActiveRecord::Base.logger로 스펙 실행: RSpec 테스트에 다음 블록을 추가하면 쿼리를 stdout으로 출력할 수 있습니다.

    before do
      ActiveRecord::Base.logger = Logger.new($stdout)
    end
    
    after do
      ActiveRecord::Base.logger = nil
    end
    

    bundle exec rspec <test_file>로 테스트를 실행하면 쿼리가 테스트 출력에 나타납니다. 이 방법은 통합 테스트에서만 올바른 쿼리를 보여 줍니다. 페이지네이션 미들웨어처럼 ActiveRecord 관계를 수정하는 구성 요소가 더 있으면 단위 테스트의 출력은 정확하지 않을 수 있습니다.

쿼리 플랜#
  • 머지 리퀘스트에 포함된 각 원시 SQL 쿼리에 대한 쿼리 플랜. 각 원시 SQL 조각 뒤에 쿼리 플랜 링크를 함께 넣습니다.
  • postgres.ai 챗봇에서 explain 명령으로 생성한 플랜의 링크를 제공합니다. explain 명령은 EXPLAIN ANALYZE를 실행합니다.
    • Database Lab에서 정확한 결과를 얻을 수 없다면 개발 환경에 데이터를 시드한 뒤 EXPLAIN ANALYZE의 출력을 대신 제공해야 할 수 있습니다. 플랜 링크는 explain.depesz.com이나 explain.dalibo.com으로 만듭니다. 이때 양식에 플랜과 사용한 쿼리를 모두 붙여 넣습니다.
  • 쿼리 플랜을 제공할 때는 충분한 데이터가 조회되는지 확인합니다.
    • 충분한 데이터로 쿼리 플랜을 만들려면 다음 ID를 사용할 수 있습니다.

      • 그룹이 관련된 쿼리에는 gitlab-org 네임스페이스(namespace_id = 9970).
      • 프로젝트가 관련된 쿼리에는 gitlab-org/gitlab-foss(project_id = 13083) 또는 gitlab-org/gitlab(project_id = 278964) 프로젝트.
        • 프로젝트 멤버십이 관련된 쿼리에서는 쿼리 플랜을 만들기 위해 이 프로젝트들의 project_namespace_id가 필요할 수 있습니다. 값은 15846663(gitlab-org/gitlab)과 15846626(gitlab-org/gitlab-foss)입니다
      • 사용자가 관련된 쿼리에는 gitlab-qa 사용자(user_id = 1614863).
        • 필요하다면 본인의 user_id 나, 쿼리 플랜을 만드는 데 사용하는 프로젝트·그룹에서 이력이 긴 사용자의 user_id를 사용할 수도 있습니다.
    • 즉 어떤 쿼리 플랜도 0건을 반환하거나 (limit 이 있는 경우) 지정한 limit보다 적은 건수를 반환해서는 안 됩니다. 배치 처리에 사용되는 쿼리라면 결과가 충분히 포함된 적절한 예시 배치를 찾아 제공해야 합니다.

      [!note] UPDATE 문은 항상 0건을 반환합니다. 어떤 행이 업데이트되는지 확인하려면 아래 줄들을 살펴봐야 합니다.

      예를 들어 UPDATE 문은 0건을 반환하지만, -> Index scan으로 시작하는 줄에서 1행을 업데이트한다는 것을 확인할 수 있습니다.

      EXPLAIN UPDATE p_ci_pipelines SET updated_at = current_timestamp WHERE id = 1606117348;
      
       ModifyTable on public.p_ci_pipelines  (cost=0.58..3.60 rows=0 width=0) (actual time=5.977..5.978 rows=0 loops=1)
        Buffers: shared hit=339 read=4 dirtied=4
        WAL: records=20 fpi=4 bytes=21800
        I/O Timings: read=4.920 write=0.000
        ->  Index Scan using ci_pipelines_pkey on public.ci_pipelines p_ci_pipelines_1  (cost=0.58..3.60 rows=1 width=18) (actual time=0.041..0.044 rows=1 loops=1)
              Index Cond: (p_ci_pipelines_1.id = 1606117348)
              Buffers: shared hit=8
              I/O Timings: read=0.000 write=0.000
      
    • 쿼리가 GitLab.com의 새 기능에 속해서 프로덕션에서 데이터를 반환하지 않는 경우에는 다음과 같이 합니다.

      • 쿼리를 분석해 로컬 환경의 플랜을 제공할 수 있습니다.
      • postgres.ai에서는 데이터 업데이트(exec UPDATE issues SET ...)와 새 테이블·칼럼 생성(exec ALTER TABLE issues ADD COLUMN ...)이 가능합니다.
    • 실제 반환 레코드 수를 확인하는 방법은 EXPLAIN 플랜 이해하기에서 자세히 다룹니다

  • 쿼리를 변경하는 경우에는 변경 전후의 SQL 쿼리와 플랜을 모두 제공하는 것이 좋습니다. 그래야 차이를 빠르게 확인할 수 있습니다.
  • 성능 개선을 보여 주는 데이터를 포함하되, 가급적 벤치마크 형태로 제공합니다.
  • 쿼리 플랜을 평가할 때는 데이터베이스에 대해 실제로 실행되는 최종 쿼리가 필요합니다. finder 나 스코프에서 ActiveRecord::Relation으로 반환되는 중간 쿼리는 분석할 필요가 없습니다. PostgreSQL 쿼리 플랜은 limit을 비롯해 최종 실행 전에 추가될 수 있는 모든 최종 파라미터에 좌우됩니다. 실제로 실행된 쿼리를 확실히 확인하는 한 가지 방법은 log/development.log를 보는 것입니다.

기존 테이블에 외래 키 추가 시 준비 사항#

  • 외래 키를 추가하기 전에 소스 테이블의 고아 행을 제거하는 마이그레이션을 포함합니다.
  • 더 이상 필요하지 않게 된 dependent: ...는 모두 제거합니다.

테이블 추가 시 준비 사항#

  • 테이블 칼럼 정렬 가이드라인에 따라 칼럼을 정렬합니다.
  • 다른 테이블의 데이터를 가리키는 칼럼에는 인덱스를 포함해 외래 키를 추가합니다.
  • WHERE, ORDER BY, GROUP BY, JOIN 같은 구문에 사용되는 필드에는 인덱스를 추가합니다.
  • 새 테이블은 db/fixtures/development/의 파일로 시드해야 합니다. 이 픽스처는 업그레이드가 정상적으로 완료되는지 확인하는 데도 사용되므로, 새 테이블에는 항상 데이터가 채워져야 합니다. 머지 리퀘스트로 추가된 테이블이 시드 후에도 비어 있으면 run-dev-fixtures-ee job 이 실패합니다.
  • 정적 데이터를 저장하는 데 데이터베이스 테이블을 사용하지 않도록 합니다. 대신 fixed items model을 사용합니다.
  • 새 테이블과 칼럼이 반드시 위험한 것은 아니지만, 시간이 지나면 일부 접근 패턴은 본질적으로 확장하기 어려워집니다. 이런 위험한 패턴을 미리 찾아내려면 접근 방식과 규모에 대한 예상을 문서로 남겨야 합니다. MR 설명에 다음 항목에 대한 답을 포함합니다.
    • 향후 3개월, 6개월, 1년 동안 새 테이블의 예상 증가량과 그 예상의 근거가 되는 가정
    • 3개월, 6개월, 1년 뒤 이 테이블의 시간당 예상 읽기·쓰기 횟수, 행이 업데이트되는 상황, 그리고 그 예상의 근거가 되는 가정
    • 예상 데이터 규모와 접근 패턴을 고려할 때 새 테이블이 GitLab.com 이나 GitLab Self-Managed 인스턴스의 가용성에 위험이 되는지, 제안한 설계가 GitLab.com과 GitLab Self-Managed 고객의 요구를 감당할 만큼 확장되는지

칼럼, 테이블, 인덱스 또는 기타 구조 제거 시 준비 사항#

  • 칼럼 삭제 가이드라인을 따릅니다.
  • 일반적으로 인덱스와 외래 키는 사후 배포 마이그레이션에서 제거하는 것이 모범 사례입니다(엄격한 규칙은 아닙니다).
    • 작은 테이블의 인덱스와 외래 키 제거는 예외입니다.
  • 인덱스를 삭제할 때는 복합 인덱스 칼럼 순서 요건을 확인해 복합 인덱스가 대체 역할을 할 수 있는지 검증합니다.
  • 복합 인덱스를 추가하면 다른 인덱스가 불필요해질 수 있으므로, 같은 마이그레이션에서 그 인덱스를 제거합니다. 예를 들어 index(column_A, column_B, column_C)를 추가하면 index(column_A, column_B)와 index(column_A) 인덱스가 불필요해집니다.

대량 업데이트 작업 사용 시 준비 사항#

ActiveRecord의 update, upsert, delete, update_all, upsert_all, delete_all, destroy_all 메서드는 데이터를 수정하고 성능이 나쁠 수 있으며, 스코프를 잘못 지정하면 데이터를 파괴할 수도 있으므로 각별히 주의해야 합니다. 이 메서드들은 공통 테이블 표현식(CTE) 구문과도 호환되지 않습니다. 이 메서드를 사용하면 Danger가 머지 리퀘스트 diff에 코멘트를 남깁니다.

쿼리 추가 또는 수정 시 준비 사항 문서에 따라 원시 SQL 쿼리와 쿼리 플랜을 머지 리퀘스트 설명에 추가하고 데이터베이스 리뷰를 요청합니다.

유용한 팁#

  • 특정 브랜치에서 마이그레이션을 적용하고 되돌리는 일이 잦다면 scripts/database/migrate.rb 를 사용해 이 과정을 더 효율적으로 처리할 수 있습니다.

데이터베이스 리뷰 방법#

기본 마이그레이션 요구 사항#

  • 데이터베이스 테스트 job(db:gitlabcom-database-testing)이 통과하는지 확인합니다.
  • db/structure.sql에 이 머지 리퀘스트의 마이그레이션과 관련된 변경만 있고 무관한 스키마 수정은 없는지 확인합니다
  • 마이그레이션을 되돌릴 수 있는지 확인하고 #down 메서드를 구현했는지 확인합니다
  • 마이그레이션이 트랜잭션 안에서 실행되거나(Rails 기본값), disable_ddl_transaction!과 함께 동시성 작업만 사용하는지 확인합니다
  • db/schema_migrations 아래의 관련 버전 파일이 추가·제거되었는지 확인합니다

스타일 및 표준 준수#

대규모 테이블 및 크기 제한#

  • 크기 임계값을 넘은 기존 테이블에 인덱스와 칼럼이 추가되지 않았는지 확인합니다. 필요하다면 작성자는 데이터베이스 프레임워크 팀에 예외 요청을 제출할 수 있습니다
  • 큰 테이블에 인덱스를 추가했고 Database Lab에서 실행 시간이 길었다면(1시간 초과) 다음과 같이 처리합니다.
    • 비동기로 추가하는 절차를 따릅니다
    • 메인테이너: 머지 리퀘스트가 머지된 뒤 #f_upcoming_release Slack 채널에서 릴리스 매니저에게 알립니다

타이밍 및 성능 표준#

  • 마이그레이션 타이밍 가이드라인을 확인합니다
  • 쿼리 실행 시간을 확인합니다(해당되는 경우). 단일 트랜잭션에서 마이그레이션이 실행하는 누적 쿼리 시간은 GitLab.com 기준 15초 안에 충분히 들어와야 하며, 그보다 훨씬 짧을수록 좋습니다
  • 일반적인 지침은 쿼리 실행 시간을 100ms 이하로 유지하는 것입니다

마이그레이션 배치 및 타이밍#

  • GitLab.com 에서의 실행 시간을 예상합니다
  • 적절한 마이그레이션 유형을 선택합니다
  • 데이터 마이그레이션은 되돌릴 수 있어야 하며, 그렇지 않다면 왜 아무 동작도 하지 않거나 되돌릴 수 없는지 주석으로 남겨야 합니다. 이는 모든 유형의 마이그레이션(일반, 사후 배포, 백그라운드 마이그레이션)에 적용됩니다

백그라운드 마이그레이션 세부 사항#

  • 배치 백그라운드 마이그레이션을 확인합니다
  • gitlab-com-database-testing 코멘트(Database Migrations (on the main database) 등의 제목)에 제공된 예상 시간이 쿼리 성능 가이드라인에 부합하는지 확인합니다
  • 백그라운드 마이그레이션은 보통 다음 용도로 사용되며, 이에 국한되지는 않습니다.
    • 큰 테이블의 데이터 마이그레이션
    • 데이터셋의 레코드마다 여러 SQL 쿼리를 수행하는 작업
  • 쿼리를 검토합니다(예를 들어 배치 크기가 적절한지 확인합니다)
  • 위 마이그레이션 배치 및 타이밍 절의 배치 가이드라인을 따릅니다

새 테이블 및 칼럼 리뷰#

  • 관계형 모델링과 설계 선택을 검토합니다
  • 명시된 접근 패턴과 데이터 양이 타당한지, 그 근거가 되는 가정이 합리적인지, 이러한 패턴이 안정성에 위험을 주는지 확인합니다
  • 칼럼이 공간을 절약하도록 정렬되었는지 확인합니다
  • 다른 테이블을 참조하는 외래 키가 있는지 확인합니다
  • 칼럼을 제거하는 경우 해당 칼럼이 이전 릴리스에서 무시 처리되었는지 확인합니다

쿼리 성능 분석#

  • 지나치게 복잡한 쿼리와 작성자가 검토를 요청한 쿼리가 있는지 확인합니다(해당되는 경우)
  • 새로 추가하거나 수정한 모든 쿼리에 대해 SQL 문과 Database Lab 쿼리 플랜이 머지 리퀘스트 설명에 모두 포함되어 있는지 확인합니다
  • 해당 쿼리에서 데이터 분포와 관련된 파라미터를 검토합니다
  • 쿼리 플랜을 확인하고 필요한 개선안을 제안합니다(예를 들어 쿼리 구조 변경, 인덱스 추가·제거 등). 미해결 질문이 있으면 #database_maintainers 채널에 문의합니다.
  • N+1 문제를 피하고 쿼리 수를 최소화합니다