데이터베이스 검토 지침
이 페이지는 데이터베이스 검토에 특화되어 있습니다. 일반적인 코드 검토에 대한 더 넓은 조언 및 가이드는 code review guide를 참조하십시오.
일반적인 과정
다음에 대해 데이터베이스 검토가 필요합니다:
- 데이터베이스 스키마에 영향을 주는 변경 또는 데이터 이관을 수행하는 경우:
db/
-
lib/gitlab/background_migration/
에 있는 파일
- 데이터베이스 도구에 대한 변경. 예를 들어:
-
lib/gitlab/database/
에 마이그레이션 또는 ActiveRecord 도우미 - 부하 분산
-
- 분명히 초과하는 SQL 쿼리를 생성하는 변경 사항. 복잡한 쿼리가 도입되고 데이터베이스 검토가 필요한지는 일반적으로 Merge Request 작성자가 결정합니다.
- ‘count’,
distinct_count
,estimate_batch_distinct_count
,sum
을 사용하는 서비스 데이터 메트릭스의 변경 사항. 이러한 메트릭은 대형 테이블에 대해 복잡한 쿼리를 가질 수 있습니다. 구현 세부 정보는 Analytics Instrumentation Guide를 참조하십시오. - ActiveRecord 객체에서
update
,upsert
,delete
,update_all
,upsert_all
,delete_all
,destroy_all
메서드를 사용하는 변경 사항.
데이터베이스 검토자는 변경 내용에서 지나치게 복잡한 쿼리를 찾아 더 자세히 검토해야 합니다. Merge Request 작성자가 특정 쿼리를 검토에 지정하지 않고 지나치게 복잡한 쿼리가 없는 경우, 마이그레이션에 집중하는 것으로 충분합니다.
필요 사항
~데이터베이스 검토를 요청할 때 다음 항목을 제공해야합니다. Merge Request 설명에 이러한 항목이 포함되어 있지 않으면 검토가 작성자에게 재할당됩니다.
마이그레이션
새로운 마이그레이션이 도입된 경우, 데이터베이스 검토자는 모든 마이그레이션에 대한 마이그레이션(db:migrate
) 및 롤백(db:rollback
)의 출력을 검토해야 합니다.
GitLab (provided by the
db:check-migrations
파이프라인 작업에 의해 제공)에 자동화된 도구를 사용하여 이 출력을 CI 작업 로그에서 제공합니다.
Merge Request 설명에 이 출력을 제공하는 것은 필수는 아니지만 리뷰어에게 도움이 될 수 있습니다. 봇은 또한 마이그레이션이 올바르게 되돌릴 수 있는지 확인합니다.
쿼리
새로운 쿼리가 도입되거나 기존 쿼리가 업데이트된 경우, 다음을 제공해야합니다:
- Merge Request에 포함된 각 raw SQL 쿼리에 대한 쿼리 계획과 각 raw SQL 스니펫 뒤에 쿼리 계획 링크
- 변경되거나 추가된 모든 쿼리의 Raw SQL (ActiveRecord 쿼리로부터 변환된 대로).
- 기존 쿼리를 업데이트하는 경우 이전 버전과 새 버전의 쿼리의 원시 SQL과 해당 쿼리 계획을 함께 제공해야합니다.
이 정보를 제공하는 방법에 대해서는 쿼리 추가 또는 수정 시의 준비를 참조하십시오.
역할과 프로세스
Merge Request 작성자의 역할은:
- 데이터베이스 검토가 필요한지 결정합니다.
- 데이터베이스 검토가 필요한 경우
~database
레이블을 추가합니다. - 데이터베이스 검토를 위한 Merge Request을 준비합니다.
- MR을 제출하기 전에 필수 아티팩트를 제공합니다.
데이터베이스 검토자의 역할은:
- 필수 아티팩트가 제공되었는지와 적절한 형식인지 확인합니다. 그렇지 않은 경우 Merge Request을 작성자에게 재할당합니다.
- MR에 대한 최초 리뷰를 수행하고 작성자에게 개선 사항을 제안합니다.
- 만족한 후, MR에 ~"database::reviewed" 레이블을 지정하고 승인하며 데이터베이스 검토자가 제안한 데이터베이스 유지 관리자로부터 리뷰를 요청합니다. 이 작업이 완료되면 리뷰어 역할을 제거합니다.
데이터베이스 유지 관리자의 역할은:
- MR에 대한 최종 데이터베이스 검토를 수행합니다.
- 추가적인 개선 사항이나 관련 변경 사항에 대해 데이터베이스 검토자 및 MR 작성자와 논의합니다.
- 마지막으로 MR을 승인하고 MR에 ~"database::approved" 레이블을 지정합니다.
- 다른 승인 사항이 대기 중이지 않은 경우 MR을 Merge하거나 요구에 따라 기타 유지자에게 전달합니다 (프론트엔드, 백엔드, 문서).
- Merge하지 않는 경우, 리뷰어 역할을 제거합니다.
리뷰 업무 분산
리뷰 업무는 리뷰어 룰렛을 사용하여 분산됩니다 (예시). Merge Request 작성자는 제안된 데이터베이스 리뷰어로부터 리뷰를 요청해야합니다. 승인하면 제안된 데이터베이스 유지 관리자로 넘겨야합니다.
리뷰어 룰렛이 데이터베이스 리뷰어 및 유지 관리자를 제안하지 않은 경우,
~database
레이블을 적용하고 danger-review
CI 작업을 다시 실행하거나
@gl-database
팀에서 누군가를 선택하세요.
데이터베이스 검토를 위한 Merge Request을 준비하는 방법
리뷰를 쉽게하고 빠르게하기 위해 다음 준비 사항을 고려하십시오.
마이그레이션 추가 시 준비
-
db/structure.sql
이 문서화된대로 업데이트되었는지 확인하고,db/schema_migrations
하위의 해당 버전 파일이 추가 또는 제거되었는지 추가로 확인합니다. - 데이터베이스 사전이 문서화된대로 업데이트되었는지 확인합니다.
-
change
메서드를 사용하거나up
를 사용할 때down
메서드를 포함하여 마이그레이션을 되돌릴 수 있도록 만드십시오.- 롤백 절차를 포함하거나 변경 사항을 롤백하는 방법을 설명하십시오.
-
db:check-migrations
파이프라인 작업이 성공적으로 실행되었는지 확인하고 마이그레이션 롤백이 예상대로 작동하는지 확인하세요.-
db:check-schema
작업이 성공적으로 실행되었는지 확인하고 롤백 시 예상치 못한 스키마 변경 사항이 발생하지 않았는지 확인하십시오. 이 작업은 스키마가 변경된 경우에만 경고를 일으킬 수 있습니다. - 리뷰 프로세스 중에 마이그레이션을 수정할 때마다 이전에 언급한 작업이 계속 성공적으로 실행되는지 확인합니다.
-
- 필요한 경우
spec/migrations
에 마이그레이션에 대한 테스트를 추가하십시오. 자세한 내용은 GitLab에서 Rails 마이그레이션 테스트를 참조하십시오. - 트랜잭션 마이그레이션의 경우 리트라이 메커니즘은 기본적으로 활성화됩니다. 트랜잭션이 아닌 마이그레이션의 경우 사용 사례 및 해결책을 확인하십시오.
- 유효한 이유가 없는 한 RuboCop 확인을 비활성화하지 않도록 하십시오.
-
대규모 테이블에 인덱스를 추가하는 경우
CREATE INDEX CONCURRENTLY
를 사용하여 Database Lab에서 실행하고 실행 시간을 MR 설명에 추가하십시오:- Database Lab의 실행 시간은 크게 달라질 수 있지만, Database Lab에서의 실행 시간이 높으면 GitLab.com에서의 실행 시간도 상당히 높을 것으로 예상됩니다.
- Database Lab의 실행 시간이
10분
을 초과하는 경우, 인덱스를 포스트 마이그레이션으로 이동해야합니다. 이 경우 해당 인덱스가 배포되는 코드가 배포되는 것을 보장하기 위해 마이그레이션과 애플리케이션 변경을 별도의 릴리스로 분리해야할 수 있습니다.
-
test
단계에서 매뉴얼으로 데이터베이스 테스트 작업인db:gitlabcom-database-testing
를 트리거하십시오.- 이 작업은 Database Lab 클론에서 마이그레이션을 실행하고 MR에 그 결과 (쿼리, 실행 시간, 크기 변경)을 게시합니다.
- 마이그레이션 실행 시간과 경고 사항을 확인하십시오.
데이터 마이그레이션을 추가할 때 준비 사항
데이터 마이그레이션은 본질적으로 리스크가 따릅니다. 제품 데이터의 손상 또는 유실로 이어질 수 있는 오류 가능성을 줄이려면 추가 조치가 필요합니다.
MR(Merge Request) 설명에 포함:
- 마이그레이션이 복원할 수 없는 경우, 사고 발생 시 데이터 변경 내용을 어떻게 되돌릴 수 있는지에 대한 세부 정보를 포함합니다. 예를 들어 레코드를 삭제하는 마이그레이션의 경우(자동으로 복원되지 않는 작업), 삭제된 레코드를 어떻게 복구할 수 있는지 설명합니다.
- 마이그레이션이 데이터를 삭제하는 경우
~data-deletion
라벨을 적용합니다. - 오류의 사용자 경험 영향에 대한 간결한 설명을 포함합니다. 예를 들어 “이슈가 예상치 못하게 에픽에서 사라질 수 있음”과 같이 기술합니다.
- 쿼리 계획(#query-plans)에서 관련된 데이터를 제공하여 쿼리가 예상대로 작동함을 보여주는 내용을 간결한 설명과 함께 포함합니다.
쿼리 추가 또는 수정 시 준비 사항
원시 SQL
- MR 설명에 원시 SQL 작성합니다. 가능하다면 pgFormatter 또는 https://paste.depesz.com과 같이 서식을 갖추고, 단일 따옴표(예:
"projects"."id"
)를 사용하고 스마트 따옴표(예:“projects”.“id”
)를 피합니다. -
매개변수를 사용하여 동적으로 생성된 쿼리의 경우, 각 변형별로 하나의 원시 SQL 쿼리를 포함해야 합니다.
예를 들어, 프로젝트에 대한 선택적 필터를 사용할 수 있는 이슈 찾기의 경우, 이슈에 대한 쿼리 버전과 프로젝트를 조인하고 필터를 적용하는 쿼리 버전을 모두 포함해야 합니다.
가능한 조합이 매우 많은 찾기나 기타 메서드가 있을 수 있습니다. 모든 가능한 생성된 쿼리를 모두 추가할 필요는 없으며, 모든 매개변수가 포함된 하나의 적절한 예와 생성된 쿼리 유형별로 하나씩 포함하면 됩니다.
- 쿼리가 항상 한도와 오프셋과 함께 사용되는 경우, 허용된 최대 한도와 0이 아닌 오프셋이 포함되어야 합니다.
쿼리 계획
- MR에 포함된 각 원시 SQL 쿼리에 대한 쿼리 계획과 쿼리 계획 뒤에 따라가는 링크를 제공합니다.
-
Postgres.ai 챗봇에서
explain
명령을 사용하여 생성된 계획에 대한 링크를 제공합니다.explain
명령은EXPLAIN ANALYZE
를 실행합니다.- Database Lab에서 정확한 그림을 얻을 수 없는 경우, 개발 환경을 구성하고
EXPLAIN ANALYZE
의 출력을 제공합니다. 계획 및 사용된 쿼리를 explain.depesz.com 또는 explain.dalibo.com에 링크하십시오.
- Database Lab에서 정확한 그림을 얻을 수 없는 경우, 개발 환경을 구성하고
- 쿼리 계획을 제공할 때 충분한 데이터를 실행했는지 확인합니다:
- 충분한 데이터로 쿼리 계획을 생성하려면 다음 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개 레코드 또는 제공된 한도 보다 더 적은 레코드를 반환하지 않아야 함을 의미합니다(한도가 포함된 경우). 쿼리가 배치에 사용되는 경우 적절한 결과가 포함된 적합한 예제 배치를 식별하고 제공해야 합니다.
- 쿼리가 GitLab.com에 데이터를 반환하지 않는 새로운 기능의 경우:
- 쿼리를 분석하고 로컬 환경에서 생성된 계획을 제공할 수 있습니다.
-
postgres.ai를 사용하여 데이터 업데이트(
exec UPDATE issues SET ...
) 및 새 테이블과 열 추가(exec ALTER TABLE issues ADD COLUMN ...
)를 생성할 수 있습니다.
- EXPLAIN 계획 이해에서 실제 반환된 레코드 수를 찾는 방법에 대한 자세한 정보
- 충분한 데이터로 쿼리 계획을 생성하려면 다음 ID를 사용할 수 있습니다:
- 쿼리 변경의 경우 변경 전과 후의 SQL 쿼리를 모두 제공하는 것이 가장 좋습니다. 이는 차이점을 빨리 파악하는 데 도움이 됩니다.
- 성능 향상을 나타내는 벤치마크 형식으로 포함된 데이터를 제공합니다.
- 쿼리 계획을 평가할 때, 실행되어야 하는 최종 쿼리가 필요합니다. finders 및 scopes에서 반환된 중간 쿼리를 분석할 필요는 없습니다. PostgreSQL 쿼리 계획은 모든 최종 매개변수에 의존하며, 한도 및 참여할 수 있는 다른 사항을 포함합니다. 실행 전 실제 쿼리가 실행되었는지 확인하는 하나의 방법은
log/development.log
를 확인하는 것입니다.
기존 테이블에 외래 키 추가 준비 사항
- 외래 키를 추가하기 전에 소스 테이블에서 고아 행을 제거하는 마이그레이션을 포함합니다.
- 더 이상 필요하지 않을 수도 있는
dependent: ...
인스턴스를 제거합니다.
테이블 추가 시 준비 사항
- 테이블 열 순서 지정 가이드라인에 따라 열을 정렬합니다.
- 다른 테이블에 포인팅하는 열에 외래 키 및 인덱스를 추가합니다.
-
WHERE
,ORDER BY
,GROUP BY
,JOIN
과 같은 문에서 사용되는 필드에 대한 인덱스를 추가합니다. - 새로운 테이블과 열은 본질적으로 리스크가 있는 것은 아니지만 시간이 지남에 따라 일부 액세스 패턴이 확장하기 어려운 경우가 있습니다. 이러한 리스크 패턴을 미리 식별하려면 새로운 테이블의 액세스 및 크기에 대한 기대사항을 문서화해야 합니다. MR 설명에 다음 질문에 대한 답변을 포함시킵니다:
- 다음 3개월, 6개월, 1년 동안 해당 테이블에 대한 예상 성장은 무엇이며, 이러한 가정은 무엇을 기반으로 하나요?
- 3개월, 6개월, 1년 동안 이 테이블이 예상하는 시간당 읽기와 쓰기는 얼마나 되며, 어떤 상황에서 행이 업데이트되나요? 이러한 가정은 무엇을 기반으로 하나요?
- 예상 데이터 양과 액세스 패턴을 기반으로 하여 새로운 테이블이 GitLab.com 또는 Self-managed 인스턴스에 가용성 리스크를 초래합니까? 제안된 디자인이 GitLab.com 및 Self-managed 고객의 요구를 지원할 수 있는 규모로 확장되는 지 확인합니다.
열, 테이블, 인덱스 또는 기타 구조물을 제거할 때의 준비
- 열 제거 지침을 준수합니다.
- 일반적으로, 배포 후 마이그레이션에서는 인덱스 및 외래 키를 제거하는 것이 좋은 방법입니다(하지만 이것은 강제 규칙은 아닙니다).
- 예외적으로 작은 테이블에서는 인덱스 및 외래 키를 제거하지 않을 수 있습니다.
- 복합 인덱스를 추가하면 다른 인덱스가 중복될 수 있으므로 동일한 마이그레이션에서 해당 인덱스를 제거하세요.
예를 들어,
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는 이러한 메서드가 사용될 때 Merge Request 차이에 주석을 달 것입니다.
쿼리 추가 또는 수정 준비에 대한 문서를 참고하여 Merge Request 설명에 원시 SQL 쿼리 및 쿼리 계획을 추가하고 데이터베이스 검토를 요청하세요.
데이터베이스 검토 방법
- 마이그레이션 확인
- 관계 모델링 및 설계 선택 사항 검토
- 새 테이블 또는 열을 추가하는 경우 액세스 패턴 및 데이터 레이아웃을 고려하세요.
- 마이그레이션을 데이터베이스 마이그레이션 스타일 가이드에 따라 확인합니다.
예를 들어
- 열 순서 확인
- 외래 키에 대한 인덱스의 존재 확인(migration_style_guide.md#adding-foreign-key-constraints)
- 마이그레이션이 트랜잭션에서 실행되거나 동시 인덱스/외래 키 도우미만 포함되도록 확인합니다(트랜잭션이 비활성화된 상태).
- 큰 테이블에 인덱스가 추가되고 실행 시간이 길어졌을 경우(1시간 이상), 데이터베이스 Lab에 알림:
- 해당 인덱스가 마이그레이션 후 추가되었는지 확인합니다.
- 유지자: Merge Request이 Merge된 후
#f_upcoming_release
Slack 채널에서 릴리스 매니저에게 알립니다.
-
db/structure.sql
의 일관성 확인 및 마이그레이션이 가능한 역방향으로 이루어졌는지 확인합니다. - 해당 버전 파일이
db/schema_migrations
에 추가 또는 제거되었는지 확인합니다. - 쿼리 실행 시간 확인(있는 경우): 단일 트랜잭션에서 실행된 누적 쿼리 시간은 GitLab.com에서
15초
이내에 편안하게 들어맞아야 합니다. - 열 제거의 경우, 해당 열이 이전 릴리스에서 무시되었는지 확인하세요(database/avoiding_downtime_in_migrations.md#dropping-columns).
- 관계 모델링 및 설계 선택 사항 검토
-
일괄 배경 마이그레이션(batched background migrations) 확인:
- GitLab.com에서의 실행에 대한 시간 추정치 설정
- 역사적인 목적으로, 해당 추정치를 Merge Request 설명에 기재하는 것이 매우 권장됩니다.
- 예상 배치 수에 따른 지연 시간을 곱합니다.
-
test
단계에서 매뉴얼으로 데이터베이스 테스트 작업(db:gitlabcom-database-testing
)을 트리거합니다. - 단일
update
가1초
미만인 경우 해당 쿼리를 일반 마이그레이션(db/migrate
내부)에 배치할 수 있습니다. - 배경 마이그레이션은 일반적으로 사용되지만 이에 국한되지는 않습니다:
- 큰 테이블에서 데이터 이동
- 데이터 집합의 개별 레코드당 다수의 SQL 쿼리 생성
- 쿼리 검토(예: 배치 크기가 적절한지 확인)
- 일반 마이그레이션보다 실행 시간이 길 수 있으므로, 배경 마이그레이션을 포스트 마이그레이션으로 다루는 것이 좋습니다:
db/migrate
대신db/post_migrate
에 배치합니다.
- GitLab.com에서의 실행에 대한 시간 추정치 설정
- 마이그레이션에 대한 시간 가이드라인 확인
- 마이그레이션이 역방향이 가능하고
#down
메서드를 구현하는지 확인합니다. - 새 테이블 마이그레이션 확인:
- 명시된 액세스 패턴 및 볼륨이 합리적인지 확인하세요. 기반으로 한 가정들은 타당해 보이는지, 이러한 패턴이 안정성에 위험을 가지고 있는지 확인하세요.
- 공간을 절약하기 위해 열을 정렬했는지 확인하세요.
- 다른 테이블을 참조하는 외래 키가 있는지 확인하세요.
- 데이터 마이그레이션 확인:
- GitLab.com에서 실행에 대한 시간 추정치 설정
- 시간에 따라 데이터 마이그레이션을 일반, 배포 후 또는 배경 마이그레이션으로 배치할 수 있습니다.
- 데이터 마이그레이션이 가능한지 또는 가능한 경우 반대로 되는 방법을 설명하는 설명을 제공해야 합니다. 이는 모든 유형의 마이그레이션(일반, 배포 후, 배경)에 적용됩니다.
- 쿼리 성능
- 지나치게 복잡한 쿼리 및 저자가 명시적으로 검토를 요청한 쿼리인 경우 확인하세요(있는 경우)
- 존재하지 않는 경우, 저자에게 Database Lab을 사용하여 SQL 쿼리 및 쿼리 계획을 제공하도록 요청하세요
- 주어진 쿼리에 대해 데이터 분포에 관한 매개변수 검토
- 쿼리 계획 확인 및 쿼리 개선 제안(쿼리, 스키마 변경, 인덱스 추가 등)
- 쿼리의 실행 시간이 100ms 미만이어야 합니다.
- N+1 문제를 피하고 쿼리 수를 최소화하세요.