# Database Review Guidelines

> 原文：[https://docs.gitlab.com/ee/development/database_review.html](https://docs.gitlab.com/ee/development/database_review.html)

*   [General process](#general-process)
    *   [Roles and process](#roles-and-process)
    *   [Distributing review workload](#distributing-review-workload)
    *   [How to prepare the merge request for a database review](#how-to-prepare-the-merge-request-for-a-database-review)
        *   [Preparation when adding migrations](#preparation-when-adding-migrations)
        *   [Preparation when adding or modifying queries](#preparation-when-adding-or-modifying-queries)
        *   [Preparation when adding foreign keys to existing tables](#preparation-when-adding-foreign-keys-to-existing-tables)
        *   [Preparation when adding tables](#preparation-when-adding-tables)
        *   [Preparation when removing columns, tables, indexes, or other structures](#preparation-when-removing-columns-tables-indexes-or-other-structures)
    *   [How to review for database](#how-to-review-for-database)
    *   [Timing guidelines for migrations](#timing-guidelines-for-migrations)

# Database Review Guidelines[](#database-review-guidelines "Permalink")

此页面特定于数据库评论. 请参阅我们的[代码审查指南](code_review.html) ，以获取有关[代码审查](code_review.html)的更广泛建议和最佳实践.

## General process[](#general-process "Permalink")

A database review is required for:

*   涉及数据库架构或执行数据迁移的更改，包括以下文件：
    *   `db/`
    *   `lib/gitlab/background_migration/`
*   对数据库工具的更改. 例如：
    *   `lib/gitlab/database/`迁移或 ActiveRecord 助手
    *   负载均衡
*   产生 SQL 查询的更改超出了显而易见的范围. 通常由合并请求的作者决定是否引入复杂查询以及是否需要数据库审查.

期望数据库审阅者在更改中查找明显复杂的查询，并仔细检查那些查询. 如果作者没有指出要审核的特定查询，并且没有明显复杂的查询，那么仅专注于审核迁移就足够了.

最好以 SQL 形式复审查询，并且通常要求作者翻译 SQL 形式的任何 ActiveRecord 查询以复审.

### Roles and process[](#roles-and-process "Permalink")

合并请求**作者**的角色是：

*   确定是否需要数据库审查.
*   如果需要数据库检查，请添加〜database 标签.
*   [Prepare the merge request for a database review](#how-to-prepare-the-merge-request-for-a-database-review).

数据库**审阅者**的角色是：

*   对 MR 进行一次初审，并向作者提出改进建议.
*   一旦满意，请用〜" database :: reviewed"重新标记 MR，批准，然后将 MR 重新分配给 Reviewer Roulette 建议的数据库**维护者** .

数据库**维护者**的作用是：

*   在 MR 上执行最终数据库审查.
*   与数据库审阅者和 MR 作者讨论进一步的改进或其他相关更改.
*   最后批准 MR，并使用〜" database :: approved"重新标记 MR
*   如果没有其他待批准的批准，则合并 MR，或根据需要将其传递给其他维护者（前端，后端，文档）.

### Distributing review workload[](#distributing-review-workload "Permalink")

使用[审阅者轮盘](code_review.html#reviewer-roulette) （ [示例](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/25181#note_147551725) ）分配[审阅](code_review.html#reviewer-roulette)工作量. 然后，MR 作者应共同指派建议的数据库**审阅者** . 当他们批准时，他们将移交给建议的数据库**维护者** .

如果审阅者轮盘赌没有建议数据库审阅者和维护者，请确保已应用〜database 标签并重新运行`danger-review` CI 作业，或从[`@gl-database`团队中](https://gitlab.com/groups/gl-database/-/group_members)选择某人.

### How to prepare the merge request for a database review[](#how-to-prepare-the-merge-request-for-a-database-review "Permalink")

为了使审核更加轻松快捷，请考虑以下准备工作.

#### Preparation when adding migrations[](#preparation-when-adding-migrations "Permalink")

*   确保`db/structure.sql`已按照[记录进行](migration_style_guide.html#schema-changes)更新.
*   通过使用`change`方法使迁移可逆，或者在使用`up`时包括`down`方法.
    *   包括回滚过程或描述如何回滚更改.
*   将所有迁移的迁移和回滚的输出添加到 MR 描述中.
    *   确保 down 方法还原`db/structure.sql`的更改.
    *   在查看过程中，只要您修改迁移，就更新迁移输出.
*   如有必要，在`spec/migrations`添加迁移测试. 有关更多详细信息，请参见[在 GitLab 上测试 Rails 迁移](testing_guide/testing_migrations_guide.html) .
*   当迁移中涉及[高流量](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3)表时，请使用[`with_lock_retries`](migration_style_guide.html#retry-mechanism-when-acquiring-database-locks)帮助程序方法. 请查看[我们文档中](migration_style_guide.html#examples)的相关[示例以](migration_style_guide.html#examples)获取用例和解决方案.
*   Ensure RuboCop checks are not disabled unless there’s a valid reason to.
*   将索引添加到[大表时](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3) ，请在`#database-lab` Slack 通道中使用`CREATE INDEX CONCURRENTLY`测试其执行，并将执行时间添加到 MR 描述中：
    *   `#database-lab`和 GitLab.com 之间的执行时间差异很大，但是`#database-lab`执行时间增加，可能暗示 GitLab.com 上的执行量也很高.
    *   如果`#database-lab`的执行时间超过`1h` ，则应将索引移至[迁移后](post_deployment_migrations.html) . 请记住，在这种情况下，您可能需要将迁移和应用程序更改分为不同的版本，以确保在部署需要索引的代码时索引就位.

#### Preparation when adding or modifying queries[](#preparation-when-adding-or-modifying-queries "Permalink")

*   在 MR 说明中编写原始 SQL. 最好用[pgFormatter](https://sqlformat.darold.net)或[paste.depesz.com](https://paste.depesz.com)很好地格式化.
*   在描述中包括相关查询的`EXPLAIN (ANALYZE, BUFFERS)`输出. 如果输出太长，请将其包装在`<details>`块中，将其粘贴到 GitLab 代码片段中，或在以下位置提供指向计划的链接： [explain.depesz.com](https://explain.depesz.com) .
*   提供查询计划时，请确保其命中足够的数据：
    *   您可以通过`#database-lab` Slack 通道或[chatops](understanding_explain_plans.html#chatops)使用 GitLab 生产副本大规模测试查询.
    *   通常， `gitlab-org`命名空间（ `namespace_id = 9970` ）和`gitlab-org/gitlab-foss` （ `project_id = 13083` ）或`gitlab-org/gitlab` （ `project_id = 278964` ）项目提供了足够的数据作为一个很好的例子.
*   对于查询的变化，最好是与*前*和变更*后*的方案一起提供的 SQL 查询. 这有助于快速发现差异.
*   包括显示性能改善的数据，最好以基准形式显示.

#### Preparation when adding foreign keys to existing tables[](#preparation-when-adding-foreign-keys-to-existing-tables "Permalink")

*   **在**添加外键**之前，**进行迁移以删除源表中的孤立行.
*   删除所有`dependent: ...`实例`dependent: ...`可能不再需要.

#### Preparation when adding tables[](#preparation-when-adding-tables "Permalink")

*   根据" [订购表列"](ordering_table_columns.html)准则[订购列](ordering_table_columns.html) .
*   将外键添加到指向其他表中数据的任何列，包括[index](migration_style_guide.html#adding-foreign-key-constraints) .
*   为在诸如`WHERE` ， `ORDER BY` ， `GROUP BY`和`JOIN`的语句中使用的字段添加索引.

#### Preparation when removing columns, tables, indexes, or other structures[](#preparation-when-removing-columns-tables-indexes-or-other-structures "Permalink")

*   遵循[有关删除列](what_requires_downtime.html#dropping-columns)的[准则](what_requires_downtime.html#dropping-columns) .
*   通常，最佳实践（但不是硬性规定）是在部署后迁移中删除索引和外键.
    *   例外包括删除小型表的索引和外键.
*   如果要添加复合索引，则另一个索引可能会变得多余，因此请在同一迁移中将其删除. 例如，添加`index(column_A, column_B, column_C)`会使索引`index(column_A, column_B)`和`index(column_A)`冗余.

### How to review for database[](#how-to-review-for-database "Permalink")

*   检查迁移
    *   审查关系建模和设计选择
    *   查看迁移遵循[数据库迁移样式指南](migration_style_guide.html) ，例如
        *   [检查列的顺序](ordering_table_columns.html)
        *   [检查索引是否存在外键](migration_style_guide.html#adding-foreign-key-constraints)
    *   确保迁移在事务中执行，或仅包含并发索引/外键助手（已禁用事务）
    *   如果在`#database-lab`上添加了指向大表的索引，并且其执行时间增加了（超过 1h）：
        *   确保在迁移后将其添加.
        *   维护者：合并请求合并后，在`#f_upcoming_release` Slack 频道`#f_upcoming_release`其通知发布管理器.
    *   检查与`db/structure.sql`一致性，并且迁移是[可逆的](migration_style_guide.html#reversibility)
    *   检查查询时间（如果有的话）：在迁移中执行的查询需要在 GitLab.com 上适应`15s`以内（最好比`15s`少）.
    *   对于列删除，请确保[在先前版本中](what_requires_downtime.html#dropping-columns)已[忽略](what_requires_downtime.html#dropping-columns)该列
*   Check [background migrations](background_migrations.html):
    *   建立在 GitLab.com 上执行的时间估计. 出于历史目的，强烈建议在合并请求描述中包括此估计.
    *   如果单个`update`低于`1s` ，则可以将查询直接放入常规迁移中（在`db/migrate`内部）.
    *   通常使用后台迁移，但不限于：
        *   在较大的表中迁移数据.
        *   对数据集中的每条记录进行大量 SQL 查询.
    *   查看查询（例如，确保批次大小合适）
    *   因为执行时间可能比常规迁移要长，所以建议将后台迁移视为后期迁移：将它们放在`db/post_migrate`而不是`db/migrate` . 请记住，后迁移是在生产中的部署后执行的.
*   Check [timing guidelines for migrations](#timing-guidelines-for-migrations)
*   检查迁移是可逆的，并实现`#down`方法
*   检查数据迁移：
    *   建立在 GitLab.com 上执行的时间估计.
    *   根据时间的不同，可以将数据迁移放在常规，部署后或后台迁移上.
    *   数据迁移也应该是可逆的，或者在可能的情况下附带有关如何逆向的描述. 这适用于所有类型的迁移（常规，部署后，后台）.
*   查询效果
    *   检查是否有任何明显复杂的查询，以及作者特别指出要进行审查的查询（如果有）
    *   如果尚不存在，请要求作者提供 SQL 查询和查询计划（例如，通过使用[chatops](understanding_explain_plans.html#chatops)或直接数据库访问）
    *   对于给定的查询，请查看有关数据分配的参数
    *   [检查查询计划](understanding_explain_plans.html)并提出对查询的改进建议（更改查询，架构或添加索引等）
    *   一般准则是查询执行时间少于 100 毫秒
    *   如果查询依赖于尚未在生产环境中进行的先前迁移（例如，索引，列），则可以使用[还原管道](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd)中[的一次性实例](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd)来建立适当的测试环境. 如果您无权访问此项目，请访问 Slack 上的#database 以获取有关如何进行的建议.
    *   避免 N + 1 问题并最大程度地减少[查询数](merge_request_performance_guidelines.html#query-counts) .

### Timing guidelines for migrations[](#timing-guidelines-for-migrations "Permalink")

通常，对于单个部署，GitLab.com 的迁移时间不应超过 1 个小时. 以下准则不是硬性规定，据估计，这些准则可将迁移时间降到最低.

**注意：**请记住，所有运行时均应根据 GitLab.com 进行测量.

| 迁移类型 | 建议执行时间 | Notes |
| --- | --- | --- |
| 定期迁移`db/migrate` | `3 minutes` | 一个有效的例外是创建索引，因为这可能需要很长时间. |
| 在`db/post_migrate`上发布迁移 | `10 minutes` |   |
| 后台迁移 |  — | 由于它们适用于较大的表，因此无法设置精确的时序准则，但是，任何单个查询的冷缓存都必须保持在`1 second`以下的执行时间. |