Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Online not null constraints: SET NOT NULL #83

Merged
merged 6 commits into from
Jan 10, 2024

Conversation

bplunkett-stripe
Copy link
Collaborator

@bplunkett-stripe bplunkett-stripe commented Jan 9, 2024

Description

Use check constraints to make SET NOT NULL constraints online

One exception: This does not yet work for partitioned tables, since we don't yet support local check constraints

Motivation

#82

Testing

Tested via unit tests

@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch from 081f29e to 41e3d6f Compare January 9, 2024 01:27
@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch 7 times, most recently from bdb3706 to 61969a5 Compare January 9, 2024 07:40
@bplunkett-stripe bplunkett-stripe added the enhancement New feature or request label Jan 9, 2024
@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch from 61969a5 to 25af9f2 Compare January 9, 2024 07:44
@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch from 25af9f2 to 9c0af84 Compare January 9, 2024 07:58
@@ -45,6 +45,7 @@ $ pg-schema-diff plan --dsn "postgres://postgres:postgres@localhost:5432/postgre
* Online index replacement: If some index is changed, the new version will be built before the old version is dropped, preventing a window where no index is backing queries
* Online check constraint builds: Check constraints are added as `INVALID` before being validated, eliminating the need
for a long access-exclusive lock on the table
* Online `ALTER ... SET NOT NULL` using check constraints to eliminate the need for an access-exclusive lock on the table
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once this gets merged in, I'll cut a follow-up PR that highlights this behavior via an example, since I think showing rather than telling will work better.

@bplunkett-stripe bplunkett-stripe changed the title Online not null constraints Online not null constraints: SET NOT NULL Jan 10, 2024
"ALTER TABLE \"public\".\"foobar\" ADD CONSTRAINT \"not_null_10111213-1415-4617-9819-1a1b1c1d1e1f\" CHECK(\"foobar\" IS NOT NULL) NOT VALID",
"ALTER TABLE \"public\".\"foobar\" VALIDATE CONSTRAINT \"not_null_10111213-1415-4617-9819-1a1b1c1d1e1f\"",
"ALTER TABLE \"public\".\"foobar\" ALTER COLUMN \"foobar\" SET NOT NULL",
"ALTER TABLE \"public\".\"foobar\" DROP CONSTRAINT \"not_null_10111213-1415-4617-9819-1a1b1c1d1e1f\"",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super cool

Copy link
Collaborator Author

@bplunkett-stripe bplunkett-stripe Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this format is much better than the manually "schema" defined tests. We should migrate all of those over except for the schemas that are impossible to recreate via DDL, e.g., invalid indexes.

alexaub-stripe
alexaub-stripe previously approved these changes Jan 10, 2024
Copy link
Collaborator

@alexaub-stripe alexaub-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Some thoughts but all non-blocking.

Comment on lines +583 to +585
"ALTER TABLE \"public\".\"foobar\" ADD CONSTRAINT \"foobar\" CHECK((foobar IS NOT NULL)) NOT VALID",
"ALTER TABLE \"public\".\"foobar\" VALIDATE CONSTRAINT \"foobar\"",
"ALTER TABLE \"public\".\"foobar\" ALTER COLUMN \"foobar\" SET NOT NULL",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing that this works without adding a system check constraint

return schema.CheckConstraint{}, fmt.Errorf("generating uuid: %w", err)
}
return schema.CheckConstraint{
Name: fmt.Sprintf("not_null_%s", uuid.String()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: maybe we can fit in pg_schema_diff to the identifier somehow? That'd help with debugging/confusion if one of these are left around, but it's not critical

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to update the temporary indexes to use this pattern, but I'm going to save that for a subsequent PR, since I also am going to switch to the UUID's to base64 encoded to make them smaller.


if isOnPreExistingColumn && isValidNotNullCC(con) {
// If the NOT NULL check constraint is on a pre-existing column, then we should ensure it is added before
// the column.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correction right?

Suggested change
// the column.
// the column alter.

pkg/diff/sql_generator.go Outdated Show resolved Hide resolved
pkg/diff/sql_generator.go Outdated Show resolved Hide resolved
Comment on lines 1694 to 1698
// If it's a not-null check constraint, we can drop the check constraint whenever convenient, e.g., after
// the column has been altered because `NOT NULL` does not depend on the type of the column.
// For all other check constraints, they can rely on the type of the column. Thus, we should drop these
// check constraint before any columns are altered because the new type might not be compatible with the old
// check constraint.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there value to allowing the NN constraints to be dropped whenever? Maybe it'd be best to add the dependency regardless just for consistency among the constraint types?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's critical we drop this last, which the topographical sort does if an obj has no deps because of the scenario where we're deleting a valid not null constraint AND changing a column to NOT NULL.

I imagine the scenario above is pretty common because it would occur for a half-complete migration, where the valid constraint was added but the SET NOT NULL never ran

return nil, fmt.Errorf("cycle detected: %+v, %+v", graph, incomingEdgeCountByVertex)
dotSB := strings.Builder{}
if err := EncodeDOT(g, &dotSB, true); err != nil {
dotSB.Reset()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dot encoding has been super useful for debugging! @kevinmingtarja

@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch 2 times, most recently from 0e15973 to 4953a1b Compare January 10, 2024 18:02
@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch from 4953a1b to 27a1517 Compare January 10, 2024 18:07
@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch from 372c33d to 7e891de Compare January 10, 2024 18:34
@bplunkett-stripe bplunkett-stripe force-pushed the bplunkett/online-not-null-constraints branch from 7e891de to ab005bd Compare January 10, 2024 18:40
@bplunkett-stripe bplunkett-stripe merged commit d091969 into main Jan 10, 2024
6 checks passed
@bplunkett-stripe bplunkett-stripe deleted the bplunkett/online-not-null-constraints branch January 10, 2024 19:24
@bplunkett-stripe bplunkett-stripe restored the bplunkett/online-not-null-constraints branch January 10, 2024 19:24
@bplunkett-stripe bplunkett-stripe deleted the bplunkett/online-not-null-constraints branch January 10, 2024 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants