summaryrefslogtreecommitdiff
path: root/doc/development/migration_style_guide.md
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 14:34:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 14:34:42 +0000
commit9f46488805e86b1bc341ea1620b866016c2ce5ed (patch)
treef9748c7e287041e37d6da49e0a29c9511dc34768 /doc/development/migration_style_guide.md
parentdfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff)
downloadgitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'doc/development/migration_style_guide.md')
-rw-r--r--doc/development/migration_style_guide.md95
1 files changed, 59 insertions, 36 deletions
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 3e993243855..4cf546173de 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -35,16 +35,36 @@ and post-deployment migrations (`db/post_migrate`) are run after the deployment
## Schema Changes
-Migrations that make changes to the database schema (e.g. adding a column) can
-only be added in the monthly release, patch releases may only contain data
-migrations _unless_ schema changes are absolutely required to solve a problem.
+Changes to the schema should be commited to `db/structure.sql`. This
+file is automatically generated by Rails, so you normally should not
+edit this file by hand. If your migration is adding a column to a
+table, that column will be added at the bottom. Please do not reorder
+columns manually for existing tables as this will cause confusing to
+other people using `db/structure.sql` generated by Rails.
+
+When your local database in your GDK is diverging from the schema from
+`master` it might be hard to cleanly commit the schema changes to
+Git. In that case you can use the `scripts/regenerate-schema` script to
+regenerate a clean `db/structure.sql` for the migrations you're
+adding. This script will apply all migrations found in `db/migrate`
+or `db/post_migrate`, so if there are any migrations you don't want to
+commit to the schema, rename or remove them. If your branch is not
+targetting `master` you can set the `TARGET` environment variable.
+
+```shell
+# Regenerate schema against `master`
+scripts/regenerate-schema
+
+# Regenerate schema against `12-9-stable-ee`
+TARGET=12-9-stable-ee scripts/regenerate-schema
+```
## What Requires Downtime?
The document ["What Requires Downtime?"](what_requires_downtime.md) specifies
various database operations, such as
-- [adding, dropping, and renaming columns](what_requires_downtime.md#adding-columns)
+- [dropping and renaming columns](what_requires_downtime.md#dropping-columns)
- [changing column constraints and types](what_requires_downtime.md#changing-column-constraints)
- [adding and dropping indexes, tables, and foreign keys](what_requires_downtime.md#adding-indexes)
@@ -307,6 +327,34 @@ def down
end
```
+**Usage with `disable_ddl_transaction!`**
+
+Generally the `with_lock_retries` helper should work with `disabled_ddl_transaction!`. A custom RuboCop rule ensures that only allowed methods can be placed within the lock retries block.
+
+```ruby
+disable_ddl_transaction!
+
+def up
+ with_lock_retries do
+ add_column :users, :name, :text
+ end
+
+ add_text_limit :users, :name, 255 # Includes constraint validation (full table scan)
+end
+```
+
+The RuboCop rule generally allows standard Rails migration methods, listed below. This example will cause a rubocop offense:
+
+```ruby
+disabled_ddl_transaction!
+
+def up
+ with_lock_retries do
+ add_concurrent_index :users, :name
+ end
+end
+```
+
### When to use the helper method
The `with_lock_retries` helper method can be used when you normally use
@@ -330,8 +378,6 @@ Example changes:
- `change_column_default`
- `create_table` / `drop_table`
-**Note:** `with_lock_retries` method **cannot** be used with `disable_ddl_transaction!`.
-
**Note:** `with_lock_retries` method **cannot** be used within the `change` method, you must manually define the `up` and `down` methods to make the migration reversible.
### How the helper method works
@@ -506,34 +552,12 @@ You can read more about adding [foreign key constraints to an existing column](d
## Adding Columns With Default Values
-When adding columns with default values to non-empty tables, you must use
-`add_column_with_default`. This method ensures the table is updated without
-requiring downtime. This method is not reversible so you must manually define
-the `up` and `down` methods in your migration class.
-
-For example, to add the column `foo` to the `projects` table with a default
-value of `10` you'd write the following:
-
-```ruby
-class MyMigration < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:projects, :foo, :integer, default: 10)
- end
-
- def down
- remove_column(:projects, :foo)
- end
-end
-```
+With PostgreSQL 11 being the minimum version since GitLab 13.0, adding columns with default values has become much easier and
+the standard `add_column` helper should be used in all cases.
-Keep in mind that this operation can easily take 10-15 minutes to complete on
-larger installations (e.g. GitLab.com). As a result, you should only add
-default values if absolutely necessary. There is a RuboCop cop that will fail if
-this method is used on some tables that are very large on GitLab.com, which
-would cause other issues.
+Before PostgreSQL 11, adding a column with a default was problematic as it would
+have caused a full table rewrite. The corresponding helper `add_column_with_default`
+has been deprecated and will be removed in a later release.
## Changing the column default
@@ -574,8 +598,7 @@ without requiring `disable_ddl_transaction!`.
## Updating an existing column
To update an existing column to a particular value, you can use
-`update_column_in_batches` (`add_column_with_default` uses this internally to
-fill in the default value). This will split the updates into batches, so we
+`update_column_in_batches`. This will split the updates into batches, so we
don't update too many rows at in a single statement.
This updates the column `foo` in the `projects` table to 10, where `some_column`
@@ -701,7 +724,7 @@ set the limit to 8-bytes. This will allow the column to hold a value up to
Rails migration example:
```ruby
-add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8)
+add_column(:projects, :foo, :integer, default: 10, limit: 8)
```
## Timestamp column type