데이터베이스 리뷰 가이드라인
이 페이지는 데이터베이스 리뷰에 구체적입니다. 일반적인 코드 리뷰에 대한 broader advice 및 best practices는 코드 리뷰 가이드를 참조하세요.
일반 프로세스
데이터베이스 리뷰가 필요한 경우:
- 데이터베이스 스키마에 영향을 미치거나 데이터 마이그레이션을 수행하는 변경 사항,
포함된 파일:
db/
lib/gitlab/background_migration/
- 데이터베이스 도구에 대한 변경. 예를 들어:
-
lib/gitlab/database/
의 마이그레이션 또는 ActiveRecord 헬퍼 - 로드 밸런싱
-
-
명백한 것을 넘어서는 SQL 쿼리를 생성하는 변경 사항. 일반적으로 병합 요청 작가가 복잡한 쿼리가 도입되고 데이터베이스 리뷰가 필요한지 여부를 결정해야 합니다.
-
count
,distinct_count
,estimate_batch_distinct_count
및sum
을 사용하는 서비스 데이터 메트릭의 변경. 이러한 메트릭은 대형 테이블에 대해 복잡한 쿼리를 가질 수 있습니다. 구현 세부정보는 분석 기기 가이드를 참조하세요. - ActiveRecord 객체에서
update
,upsert
,delete
,update_all
,upsert_all
,delete_all
또는destroy_all
메서드를 사용하는 변경 사항.
데이터베이스 리뷰어는 변경 사항에서 지나치게 복잡한 쿼리를 찾아 이를 더 면밀히 검토해야 합니다. 작성자가 리뷰를 위한 특정 쿼리를 지적하지 않거나 지나치게 복잡한 쿼리가 없는 경우, 마이그레이션 검토에 집중하는 것으로 충분합니다.
필수
데이터베이스 리뷰를 요청할 때 다음 아티팩트를 제공해야 합니다.
병합 요청 설명에 이러한 항목이 포함되지 않으면, 리뷰는 작성자에게 다시 할당됩니다.
마이그레이션
새 마이그레이션이 도입된 경우, 데이터베이스 리뷰어는 모든 마이그레이션의 마이그레이션(db:migrate
) 및 롤백(db:rollback
) 출력을 검토해야 합니다.
우리는 GitLab를 위한 자동화 도구(db:check-migrations
](database/dbcheck-migrations-job.md) 파이프라인 작업 제공)로 CI 작업 로그에서 이 출력을 제공합니다.
작성자가 이 출력을 병합 요청 설명에 제공할 필요는 없지만, 제공하는 것이 리뷰어에게 도움이 될 수 있습니다. 봇은 마이그레이션이 올바르게 복원 가능한지 확인합니다.
쿼리
새로운 쿼리가 도입되었거나 기존 쿼리가 업데이트된 경우, 다음을 제공해야 합니다:
-
병합 요청에 포함된 각 원시 SQL 쿼리에 대한 쿼리 계획과 각각의 원시 SQL 스니펫 뒤에 쿼리 계획의 링크를 추가합니다.
-
변경되거나 추가된 모든 쿼리의 원시 SQL (ActiveRecord 쿼리에서 변환된 내용).
- 기존 쿼리를 업데이트하는 경우, 쿼리의 오래된 버전과 새 버전의 원시 SQL을 함께 제공해야 하며, 각 쿼리 계획도 포함해야 합니다.
정보 제공 방법에 대한 내용은 쿼리를 추가하거나 수정할 때 준비를 참조하세요.
역할 및 프로세스
병합 요청 작성자의 역할:
-
데이터베이스 리뷰가 필요한지 결정합니다.
-
데이터베이스 리뷰가 필요하다면,
~database
레이블을 추가합니다. -
MR 제출 전에 필수 아티팩트를 제공합니다.
데이터베이스 리뷰어의 역할:
-
필수 아티팩트가 제공되었고 올바른 형식인지 확인합니다. 제공되지 않은 경우, 병합 요청을 작성자에게 다시 할당합니다.
-
MR에 대한 첫 번째 검토를 수행하고 작성자에게 개선 사항을 제안합니다.
-
만족할 경우, MR을 ~"database::reviewed"로 레이블 변경하고 승인한 후, 리뷰어 로렛이 제안한 데이터베이스 유지 관리자에게 리뷰 요청을 합니다.
-
이 작업이 완료되면 자신을 리뷰어에서 제거합니다.
데이터베이스 유지 관리자의 역할:
-
MR에 대한 최종 데이터베이스 리뷰를 수행합니다.
-
데이터베이스 리뷰어 및 MR 작성자와 함께 추가 개선 사항이나 기타 관련 변경 사항을 논의합니다.
-
마지막으로 MR을 승인하고 MR을 ~"database::approved"로 레이블 변경합니다.
-
다른 승인이 대기 중이지 않으면 MR을 병합하거나 필요한 경우 다른 유지 관리자(프론트엔드, 백엔드, 문서)에게 전달합니다.
- 병합하지 않으면 자신을 리뷰어에서 제거합니다.
리뷰 작업 분배하기
리뷰 작업은 리뷰어 룰렛을 사용하여 분배됩니다 (예시). MR 작성자는 제안된 데이터베이스 리뷰어에게 리뷰를 요청해야 합니다. 리뷰어가 서명하면 제안된 데이터베이스 유지 관리자에게 전달됩니다.
리뷰어 룰렛이 데이터베이스 리뷰어 및 유지 관리자를 제안하지 않았다면,
~database
레이블을 적용하고
danger-review
CI 작업을 다시 실행하거나
@gl-database
팀에서 누군가를 선택하세요.
데이터베이스 리뷰를 위한 병합 요청 준비 방법
리뷰를 더 쉽게 하고, 따라서 더 빠르게 진행되도록 하기 위해 다음 준비 사항을 고려하세요.
마이그레이션 추가 시 준비 사항
-
db/structure.sql
이 문서화된 대로 업데이트되었는지 확인하고, 추가로db/schema_migrations
아래의 관련 버전 파일이 추가되었거나 제거되었는지 확인하세요. -
데이터베이스 사전이 문서화된 대로 업데이트되었는지 확인하세요.
-
마이그레이션을 되돌릴 수 있도록
change
메소드를 사용하거나up
을 사용할 때down
메소드를 포함하세요.- 롤백 절차를 포함하거나 변경 사항을 롤백하는 방법을 설명하세요.
-
db:check-migrations
파이프라인 작업이 성공적으로 실행되었는지 확인하고 마이그레이션 롤백이 예상대로 수행되는지 확인하세요.-
db:check-schema
작업이 성공적으로 실행되었고 롤백 시 예상치 못한 스키마 변경이 없는지 확인하세요. 이 작업은 스키마가 변경되었을 경우 경고만 표시할 수 있습니다. -
리뷰 과정 중 마이그레이션을 수정할 때 이전에 언급한 작업들이 계속 성공하는지 확인하세요.
-
-
필요 시
spec/migrations
에 마이그레이션 테스트를 추가하세요. GitLab에서 Rails 마이그레이션 테스트하기를 참조하세요. -
모든 트랜잭션 마이그레이션에 대해 기본적으로 잠금 재시도가 활성화되어 있습니다. 비트랜잭션 마이그레이션의 경우 사용 사례와 솔루션에 대한 관련 문서를 참조하세요.
-
유효한 이유가 없는 한 RuboCop 검사가 비활성화되지 않았는지 확인하세요.
-
대형 테이블에 인덱스를 추가할 때는 데이터베이스 실험실에서
CREATE INDEX CONCURRENTLY
를 사용하여 실행을 테스트하고 실행 시간을 MR 설명에 추가하세요: -
test
단계에서 수동으로 데이터베이스 테스트 작업(db:gitlabcom-database-testing
)을 트리거하세요.-
이 작업은 데이터베이스 실험실 클론에서 마이그레이션을 실행하고 MR에 결과(쿼리, 실행 시간, 크기 변화)를 게시합니다.
-
마이그레이션 실행 시간 및 경고 사항을 검토하세요.
-
데이터 마이그레이션 추가 시 준비 사항
데이터 마이그레이션은 본질적으로 위험이 따릅니다. 생산 데이터의 손상 또는 손실로 이어질 수 있는 오류 가능성을 줄이기 위한 추가 작업이 필요합니다.
MR 설명에 포함해야 할 내용:
-
마이그레이션 자체가 되돌릴 수 없는 경우, 사고 발생 시 데이터 변경을 되돌릴 수 있는 방법에 대한 세부 사항. 예를 들어, 레코드를 삭제하는 마이그레이션의 경우(대부분 자동으로 되돌릴 수 없는 작업) 삭제된 레코드를 어떻게 복구할 수 있을지에 대한 내용.
-
마이그레이션이 데이터를 삭제하는 경우,
~data-deletion
레이블을 적용합니다. -
오류의 가능한 사용자 경험 영향에 대한 간결한 설명; 예를 들어, “문제가 Epics에서 예상치 않게 사라질 수 있습니다.”
-
쿼리가 예상대로 작동함을 나타내는 쿼리 계획에서 관련 데이터; 수정되거나 삭제된 레코드의 대략적인 수와 같은 정보.
쿼리 추가 또는 수정 시 준비 사항
원시 SQL
-
MR 설명에 원시 SQL을 작성합니다. 가능하면 pgFormatter 또는 https://paste.depesz.com를 사용하여 예쁘게 형식을 맞추고 정규 따옴표(예:
"projects"."id"
)를 사용하고 스마트 따옴표(예:“projects”.“id”
)는 피합니다. -
매개변수를 사용하여 동적으로 생성된 쿼리의 경우 각 변형에 대해 하나의 원시 SQL 쿼리가 있어야 합니다.
예를 들어, 선택적 필터를 매개변수로 사용할 수 있는 문제발견기는 문제에 대한 쿼리 버전과 문제 및 프로젝트를 조인하고 필터를 적용하는 쿼리 버전을 모두 포함해야 합니다.
생성된 쿼리가 매우 많은 변형을 생성할 수 있는 발견기 또는 기타 방법이 있습니다. 가능한 모든 생성된 쿼리를 포함할 필요는 없으며, 모든 매개변수를 포함한 쿼리 하나와 생성된 각 유형의 쿼리 하나만 포함하면 됩니다.
예를 들어, 조인이나 그룹화 절이 선택인 경우, 그룹화 절이 없는 버전과 조인 수가 적은 버전도 적절한 필터를 유지하며 포함해야 합니다.
-
쿼리가 항상 한계와 오프셋으로 사용되는 경우, 항상 최대 허용 한계를 사용하고 비 0 오프셋이 포함되어야 합니다.
쿼리 계획
-
MR에 포함된 각 원시 SQL 쿼리에 대한 쿼리 계획과 각 원시 SQL 스니펫 뒤에 쿼리 계획 링크를 제공합니다.
-
postgres.ai 챗봇에서
explain
명령을 사용하여 생성된 계획에 대한 링크를 제공합니다.explain
명령은EXPLAIN ANALYZE
를 실행합니다.- 데이터베이스 실험실에서 정확한 그림이 파악되기 어려운 경우, 개발 환경을 시딩하고 대신
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
(forgitlab-org/gitlab
) 및15846626
(forgitlab-org/gitlab-foss
)입니다.
- 프로젝트의 구성원 자격과 관련된 쿼리의 경우, 이러한 프로젝트의
-
사용자와 관련된 쿼리의 경우
gitlab-qa
사용자 (user_id = 1614863
).- 선택적으로 귀하의
user_id
또는 쿼리 계획 생성을 위해 사용된 프로젝트 또는 그룹 내에서 오랜 기록을 가진 사용자의user_id
도 사용할 수 있습니다.
- 선택적으로 귀하의
-
-
이는 쿼리 계획이 0 레코드 또는 제공된 한계보다 적은 레코드를 반환하지 않아야 함을 의미합니다(제한이 포함된 경우). 쿼리가 배치에서 사용되는 경우, 적절한 샘플 배치와 포함된 결과가 식별되고 제공되어야 합니다.
-
쿼리가 GitLab.com의 새로운 기능에 속하고 따라서 생산 환경에서 데이터를 반환하지 않는 경우:
-
쿼리를 분석하고 로컬 환경에서 계획을 제공해야 할 수 있습니다.
-
postgres.ai는 데이터를 업데이트(
exec UPDATE issues SET ...
)하고 새로운 테이블과 열을 만들 수 있습니다(exec ALTER TABLE issues ADD COLUMN ...
).
-
-
EXPLAIN 계획 이해하기에서 실제 반환된 레코드 수를 찾는 방법에 대한 추가 정보.
-
-
쿼리 변경의 경우, 변경 이전 및 _이후_의 SQL 쿼리와 함께 계획을 제공하는 것이 좋습니다. 이는 차이점을 빠르게 찾을 수 있도록 돕습니다.
-
성능 향상을 보여주는 데이터 포함, 가능하면 벤치마크 형식으로 제공.
-
쿼리 계획 평가 시, 우리는 데이터베이스에서 실행될 최종 쿼리가 필요합니다.
ActiveRecord::Relation
에서 반환되는 중간 쿼리에 대한 분석이 필요하지 않습니다.PostgreSQL 쿼리 계획은 한계 및 최종 실행 전 추가될 수 있는 기타 요소를 포함하는 모든 최종 매개변수에 따라 달라집니다.
실제 실행된 쿼리를 확인하는 한 가지 방법은
log/development.log
를 확인하는 것입니다.
외래 키를 기존 테이블에 추가할 때의 준비 사항
- 외래 키를 추가하기 전에 소스 테이블에서 고아 행을 제거하는 마이그레이션을 포함하세요.
- 더 이상 필요하지 않을 수 있는
dependent: ...
인스턴스를 제거하세요.
테이블 추가 시의 준비 사항
- 테이블 열 순서 지정 가이드라인에 따라 열의 순서를 정리하세요.
- 다른 테이블의 데이터에 포인터를 가진 모든 열에 외래 키를 추가하세요. 여기에는 인덱스도 포함됩니다.
-
WHERE
,ORDER BY
,GROUP BY
및JOIN
등의 문에서 사용되는 필드에 대해 인덱스를 추가하세요. - 새로운 테이블은
db/fixtures/development/
의 파일로 시드(seed)되어야 합니다. 이러한 픽스처는 업그레이드가 성공적으로 완료되는지 보장하는 데도 사용되므로 새로운 테이블이 항상 채워지는 것이 중요합니다. - 새로운 테이블과 열은 반드시 위험한 것은 아니지만 시간이 지나면서 일부 액세스 패턴은 본질적으로 확장하기 어려울 수 있습니다. 이러한 위험한 패턴을 미리 식별하기 위해 액세스 및 크기에 대한 기대치를 문서화해야 합니다. MR 설명에 다음 질문에 대한 답변을 포함하세요:
- 새로운 테이블의 향후 3개월, 6개월, 1년 동안의 예상 성장률은 얼마입니까? 이러한 가정은 무엇에 기반하나요?
- 이 테이블의 3개월, 6개월, 1년 후 예상되는 시간당 읽기 및 쓰기 수는 얼마입니까? 어떤 상황에서 행이 업데이트됩니까? 이러한 가정은 무엇에 기반하나요?
- 예상 데이터 볼륨과 액세스 패턴에 따라, 새로운 테이블이 GitLab.com 또는 자기 관리 인스턴스에 가용성 위험을 초래합니까? 제안된 디자인이 GitLab.com 및 자기 관리 고객의 요구를 지원할 수 있습니까?
열, 테이블, 인덱스 또는 기타 구조를 제거할 때의 준비 사항
- 열 제거에 대한 가이드라인을 따르세요.
- 일반적으로 포스트 배포 마이그레이션에서 인덱스와 외래 키를 제거하는 것이 모범 사례입니다(단단한 규칙은 아님).
- 예외로는 작은 테이블에 대한 인덱스와 외래 키를 제거하는 경우가 있습니다.
- 복합 인덱스를 추가하는 경우 다른 인덱스가 중복될 수 있으므로 동일한 마이그레이션에서 제거하세요.
예를 들어index(column_A, column_B, column_C)
를 추가하면index(column_A, column_B)
및index(column_A)
인덱스가 중복됩니다.
대량 업데이트 작업을 사용할 때의 준비 사항
update
, upsert
, delete
, update_all
, upsert_all
, delete_all
또는 destroy_all
ActiveRecord 메소드는 데이터를 수정하므로 주의가 필요하며 성능이 저하될 수 있습니다. 또는 잘못된 범위로 인해 데이터를 손실할 수 있습니다. 이러한 메소드는 공통 테이블 표현(CTE) 문과 호환되지 않습니다.
Danger는 이러한 메소드가 사용될 때 머지 요청의 차이에 댓글을 달 것입니다.
쿼리 추가 또는 수정 준비 문서를 따르세요
원시 SQL 쿼리 및 쿼리 계획을 머지 요청 설명에 추가하고 데이터베이스 리뷰를 요청하세요.
데이터베이스 검토 방법
- 마이그레이션 확인
- 관계형 모델링 및 디자인 선택 사항 검토
- 새로운 테이블이나 열이 추가되면 액세스 패턴 및 데이터 레이아웃을 고려하세요.
- 마이그레이션이 데이터베이스 마이그레이션 스타일 가이드를 준수하는지 검토.
예를 들어, - 마이그레이션이 트랜잭션 내에서 실행되거나 단지 동시 인덱스/외래 키 도우미만 포함되어 있는지 확인하세요(트랜잭션 비활성화).
- 대형 테이블에 인덱스가 추가되고 그 실행 시간이 높았던 경우 (1시간 이상) Database Lab:
- 포스트 마이그레이션에서 추가되었는지 확인하세요.
- 유지 관리자: 머지 요청이 머지된 후,
#f_upcoming_release
슬랙 채널에서 릴리스 관리자에게 알리세요.
-
db/structure.sql
과의 일관성을 확인하고 마이그레이션이 되돌릴 수 있는지 확인하세요. -
db/schema_migrations
에서 관련 버전 파일이 추가되거나 제거되었는지 확인하세요. - 쿼리 시간 확인(있는 경우): 단일 트랜잭션 내에서 마이그레이션에서 실행된 누적 쿼리 시간은 GitLab.com에서
15s
이하로 편안하게 적합해야 합니다 - 바람직하게는 훨씬 적어야 합니다. - 열을 제거하는 경우, 해당 열이 이전 릴리스에서 무시되었는지 확인하세요.
- 관계형 모델링 및 디자인 선택 사항 검토
-
배치된 백그라운드 마이그레이션 확인:
- GitLab.com에서 실행 시간 추정치를 설정하세요. 역사적 목적을 위해 이 추정치를 머지 요청 설명에 포함하는 것이 강력히 권장됩니다.
이는 예상 배치 수 배에 지연 간격이 될 수 있습니다. -
test
단계에서 데이터베이스 테스트 작업(db:gitlabcom-database-testing
)을 수동으로 트리거하세요. - 단일
update
가1s
보다 짧은 경우, 쿼리를 정규 마이그레이션(db/migrate
내)에 직접 배치할 수 있습니다. - 백그라운드 마이그레이션은 일반적으로 사용되며, 구체적으로는 다음을 포함할 수 있습니다:
- 대형 테이블에서 데이터 이관.
- 데이터 세트의 각 레코드에 대해 많은 SQL 쿼리 수행.
- 쿼리 검토(예를 들어, 배치 크기가 적절한지 확인)
- 실행 시간이 일반 마이그레이션보다 길 수 있으므로, 백그라운드 마이그레이션을 후속 마이그레이션으로 간주하고
db/post_migrate
에 배치하는 것이 좋습니다.
- GitLab.com에서 실행 시간 추정치를 설정하세요. 역사적 목적을 위해 이 추정치를 머지 요청 설명에 포함하는 것이 강력히 권장됩니다.
- 마이그레이션의 시간 가이드라인 확인
- 마이그레이션이 되돌릴 수 있는지 확인하고
#down
메소드를 구현하세요. - 새로운 테이블 마이그레이션 확인:
- 명시된 액세스 패턴 및 볼륨이 합리적인가요? 이들이 기반한 가정은 타당해 보이나요? 이러한 패턴이 안정성에 위험을 초래하나요?
- 열이 공간을 절약하기 위해 정렬되었는지?
- 다른 테이블에 대한 참조에 대한 외래 키가 있나요?
- 테이블이
db/fixtures/development/
에 픽스처가 있나요?
- 데이터 마이그레이션 확인:
- GitLab.com에서 실행 시간 추정치를 설정하세요.
- 시간에 따라 데이터 마이그레이션은 정규, 포스트 배포 또는 백그라운드 마이그레이션에 배치할 수 있습니다.
- 데이터 마이그레이션도 되돌릴 수 있거나 가능한 경우 되돌리는 방법에 대한 설명이 있어야 합니다.
이는 모든 유형의 마이그레이션(정규, 포스트 배포, 백그라운드)에 적용됩니다.
- 쿼리 성능
- 지나치게 복잡한 쿼리 및 저자가 구체적으로 검토를 요청한 쿼리가 있는지 확인하세요(있는 경우).
- 없으면 저자에게 SQL 쿼리 및 쿼리 계획을 제공해 달라고 요청하세요.
Database Lab를 사용하여. - 주어진 쿼리에 대해 데이터 분포에 대한 매개변수를 검토하세요.
-
쿼리 계획을 확인하고 쿼리를 개선하기 위해 변경 제안을 하세요.
(쿼리 변경, 스키마 변경 또는 인덱스 및 유사한 것 추가). - 쿼리는 100ms 실행 시간 이하로 오는 것이 일반적인 지침입니다.
- N+1 문제를 피하고 쿼리 수를 최소화하세요.
유용한 팁
- 특정 브랜치에서 마이그레이션을 적용하고 되돌리는 경우가 많다면, 이 프로세스를 더 효율적으로 만들기 위해
scripts/database/migrate.rb
를 사용해 보세요.