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

sql: fix FK validation join implementation #34365

Merged
merged 1 commit into from
Feb 5, 2019

Conversation

thoszhang
Copy link
Contributor

This PR updates the SQL query used for VALIDATE CONSTRAINT for foreign keys.
The new implementation is compatible with the recent changes to FK matching
semantics (both MATCH FULL and MATCH SIMPLE). It also uses a merge join, which
will improve performance significantly compared to the old hash join
implementation.

Release note (sql change): VALIDATE CONSTRAINT for foreign keys is now
compatible with the new MATCH FULL and MATCH SIMPLE semantics, and is more
performant.

Fixes #33452

@thoszhang thoszhang requested review from dt, BramGruneir and a team January 29, 2019 16:56
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@knz
Copy link
Contributor

knz commented Jan 29, 2019

Thank you for doing this! I will let David and Bram comment on the correctness, but a thought: do you think there's a way to prepare the logical plan for the validation query during the planning phase, so that it would show up in the output of EXPLAIN?

@thoszhang
Copy link
Contributor Author

thoszhang commented Jan 29, 2019

@knz probably. But we're planning to move the validation query out of the user transaction and have it happen asynchronously (by adding a mutation and moving it through the schema changer), at which point AFAIK it wouldn't be possible. We probably ultimately also want to implement a backfiller instead of using SQL to do this validation as well.

(The future changes I'm describing are implemented for check constraints in #34301)

@knz
Copy link
Contributor

knz commented Jan 29, 2019

Thank you. If done asynchronously (in a job I assume) but we're careful to use standard internal executor machinery, the user can still go and inspect the plan using the statement stats page (this shows logical plans now). So that UX interest will be satisifed this way.

Copy link
Contributor

@vivekmenezes vivekmenezes left a comment

Choose a reason for hiding this comment

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

Nice work on this. You should probably in a followup PR add this constraint validation to a roachtest that already contains the FK relationship. Thanks!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @BramGruneir, @dt, and @lucy-zhang)


pkg/sql/check.go, line 77 at r1 (raw file):

}

func matchFullUnacceptableKeyQuery(

Can you add a comment about what you're trying to do here?


pkg/sql/check.go, line 149 at r1 (raw file):

	}

	if srcIdx.ForeignKey.Match == sqlbase.ForeignKeyReference_FULL {

Can you add a comment here about why you need to run two queries in order to validate the constraint: the one below and the default one. Thanks!


pkg/sql/logictest/testdata/logic_test/fk, line 1568 at r1 (raw file):

ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok

Great tests!

@thoszhang thoszhang force-pushed the validate-fk branch 2 times, most recently from 84f38d9 to 4cc4686 Compare January 31, 2019 22:16
Copy link
Contributor Author

@thoszhang thoszhang left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @BramGruneir, @dt, @lucy-zhang, and @vivekmenezes)


pkg/sql/check.go, line 77 at r1 (raw file):

Previously, vivekmenezes wrote…

Can you add a comment about what you're trying to do here?

Done.


pkg/sql/check.go, line 149 at r1 (raw file):

Previously, vivekmenezes wrote…

Can you add a comment here about why you need to run two queries in order to validate the constraint: the one below and the default one. Thanks!

Done.

Copy link
Contributor

@vivekmenezes vivekmenezes left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @BramGruneir, @dt, and @lucy-zhang)

Copy link
Member

@BramGruneir BramGruneir left a comment

Choose a reason for hiding this comment

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

This is great! I'm excited we're finally going to be able to do this.

I've left some comments.

Reviewed 1 of 2 files at r1, 1 of 1 files at r2.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @lucy-zhang)


pkg/sql/check.go, line 120 at r2 (raw file):

	return fmt.Sprintf(
		`SELECT %s FROM (SELECT * FROM %s@%s WHERE %s) AS s LEFT OUTER JOIN %s@%s AS t ON %s WHERE %s IS NULL LIMIT 1`,

It would be really great to see a comment with an example or two of how this will look. With all the placeholders, it's hard to mentally ensure it looks correct. (and the same for the query from matchFullUnacceptableKeyQuery)

For example, what's the point of the AS s and AS t if the alias is not used?


pkg/sql/logictest/testdata/logic_test/fk, line 1382 at r2 (raw file):


# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.
statement ok

Instead of just updating the one test, could you make this two separate tests?

Also, if you could use subtests, it would make this a lot more readable.


pkg/sql/logictest/testdata/logic_test/fk, line 1588 at r2 (raw file):

);

# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.

Again, please just duplicate the test, once with validation and once without. We need to test both scenarios. Pretty easy to do with the subtests.

@thoszhang thoszhang force-pushed the validate-fk branch 2 times, most recently from 7a4b5cd to 5ea4c0a Compare February 4, 2019 22:00
Copy link
Contributor Author

@thoszhang thoszhang left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @BramGruneir and @lucy-zhang)


pkg/sql/check.go, line 120 at r2 (raw file):

Previously, BramGruneir (Bram Gruneir) wrote…

It would be really great to see a comment with an example or two of how this will look. With all the placeholders, it's hard to mentally ensure it looks correct. (and the same for the query from matchFullUnacceptableKeyQuery)

For example, what's the point of the AS s and AS t if the alias is not used?

Done. (The aliases get used in the WHERE and ON clauses but it's not the easiest to see... I added a comment)


pkg/sql/logictest/testdata/logic_test/fk, line 1382 at r2 (raw file):

Previously, BramGruneir (Bram Gruneir) wrote…

Instead of just updating the one test, could you make this two separate tests?

Also, if you could use subtests, it would make this a lot more readable.

Done.


pkg/sql/logictest/testdata/logic_test/fk, line 1588 at r2 (raw file):

Previously, BramGruneir (Bram Gruneir) wrote…

Again, please just duplicate the test, once with validation and once without. We need to test both scenarios. Pretty easy to do with the subtests.

Done.

Copy link
Member

@BramGruneir BramGruneir left a comment

Choose a reason for hiding this comment

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

:lgtm:

Just a quick comment on the MATCH FULL check.

Reviewed 2 of 2 files at r3.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @lucy-zhang)


pkg/sql/check.go, line 120 at r2 (raw file):

Previously, lucy-zhang (Lucy Zhang) wrote…

Done. (The aliases get used in the WHERE and ON clauses but it's not the easiest to see... I added a comment)

Ah, I can see it now. Thanks!


pkg/sql/check.go, line 87 at r3 (raw file):

// SELECT * FROM child@c_idx
// WHERE
//   NOT (a_id IS NULL AND b_id IS NULL OR a_id IS NOT NULL AND b_id IS NOT NULL)

This is a little convoluted.

For the null case, you can use COALESCE(col1, col2, col3) IS NULL

And could you add some parentheses to make this a little earlier to read? Relying on the order of operations is a little tough.

Copy link
Contributor Author

@thoszhang thoszhang left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @BramGruneir and @lucy-zhang)


pkg/sql/check.go, line 87 at r3 (raw file):

Previously, BramGruneir (Bram Gruneir) wrote…

This is a little convoluted.

For the null case, you can use COALESCE(col1, col2, col3) IS NULL

And could you add some parentheses to make this a little earlier to read? Relying on the order of operations is a little tough.

Done.

This PR updates the SQL query used for VALIDATE CONSTRAINT for foreign keys.
The new implementation is compatible with the recent changes to FK matching
semantics (both MATCH FULL and MATCH SIMPLE). It also uses a merge join, which
will improve performance significantly compared to the old hash join
implementation.

Release note (sql change): VALIDATE CONSTRAINT for foreign keys is now
compatible with the new MATCH FULL and MATCH SIMPLE semantics, and is more
performant.

Release note: None
Copy link
Member

@BramGruneir BramGruneir left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewed 2 of 2 files at r4.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @lucy-zhang)

@thoszhang
Copy link
Contributor Author

bors r+

craig bot pushed a commit that referenced this pull request Feb 5, 2019
34365: sql: fix FK validation join implementation r=lucy-zhang a=lucy-zhang

This PR updates the SQL query used for VALIDATE CONSTRAINT for foreign keys.
The new implementation is compatible with the recent changes to FK matching
semantics (both MATCH FULL and MATCH SIMPLE). It also uses a merge join, which
will improve performance significantly compared to the old hash join
implementation.

Release note (sql change): VALIDATE CONSTRAINT for foreign keys is now
compatible with the new MATCH FULL and MATCH SIMPLE semantics, and is more
performant.

Fixes #33452

Co-authored-by: Lucy Zhang <[email protected]>
@craig
Copy link
Contributor

craig bot commented Feb 5, 2019

Build succeeded

@craig craig bot merged commit e53dab6 into cockroachdb:master Feb 5, 2019
@thoszhang thoszhang deleted the validate-fk branch February 12, 2019 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants