From 15cb30cc7ef64ae818e6e0a080d33266b97f24a3 Mon Sep 17 00:00:00 2001 From: Shuaipeng Yu Date: Tue, 19 May 2020 14:55:01 +0800 Subject: [PATCH 1/5] reference: update constraints.md Signed-off-by: Shuaipeng Yu --- constraints.md | 212 ++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 108 deletions(-) diff --git a/constraints.md b/constraints.md index 061da8919d16..809e45ee1967 100644 --- a/constraints.md +++ b/constraints.md @@ -6,67 +6,7 @@ aliases: ['/docs-cn/dev/reference/sql/constraints/'] # 约束 -TiDB 支持的基本约束与 MySQL 的基本相同,但有以下区别: - -- 默认对唯一约束进行[惰性检查](/transaction-overview.md#事务的惰性检查)。通过在事务提交时再进行批量检查,TiDB 能够减少网络开销、提升性能。您可通过设置 `tidb_constraint_check_in_place` 为 `TRUE` 改变此行为。 - -- TiDB 支持创建外键约束,但不会在 DML 语句中对外键进行约束(即外键约束不生效)。 - -## 外键约束 - -目前,TiDB 支持创建外键。例如: - -```sql -CREATE TABLE users ( - id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, - doc JSON -); -CREATE TABLE orders ( - id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, - user_id INT NOT NULL, - doc JSON, - FOREIGN KEY fk_user_id (user_id) REFERENCES users(id) -); -``` - -{{< copyable "sql" >}} - -```sql -SELECT table_name, column_name, constraint_name, referenced_table_name, referenced_column_name -FROM information_schema.key_column_usage WHERE table_name IN ('users', 'orders'); -``` - -``` -+------------+-------------+-----------------+-----------------------+------------------------+ -| table_name | column_name | constraint_name | referenced_table_name | referenced_column_name | -+------------+-------------+-----------------+-----------------------+------------------------+ -| users | id | PRIMARY | NULL | NULL | -| orders | id | PRIMARY | NULL | NULL | -| orders | user_id | fk_user_id | users | id | -+------------+-------------+-----------------+-----------------------+------------------------+ -3 rows in set (0.00 sec) -``` - -TiDB 也支持使用 `ALTER TABLE` 命令来删除外键(`DROP FOREIGN KEY`)和添加外键(`ADD FOREIGN KEY`): - -{{< copyable "sql" >}} - -```sql -ALTER TABLE orders DROP FOREIGN KEY fk_user_id; -ALTER TABLE orders ADD FOREIGN KEY fk_user_id (user_id) REFERENCES users(id); -``` - -### 注意 - -* TiDB 支持外键是为了在将其他数据库迁移到 TiDB 时,不会因为此语法报错。但是,TiDB 不会在 DML 语句中对外键进行约束。例如,即使 `users` 表中不存在 `id=123` 的记录,下列事务也能提交成功: - - ``` - START TRANSACTION; - INSERT INTO orders (user_id, doc) VALUES (123, NULL); - COMMIT; - ``` - -* TiDB 在执行 `SHOW CREATE TABLE` 语句的结果中不显示外键信息。 +TiDB 支持的约束与 MySQL 的基本相同。 ## 非空约束 @@ -118,61 +58,67 @@ Query OK, 1 row affected (0.03 sec) * 第三条 `INSERT` 语句成功,因为 `last_login` 列没有被明确地指定为 `NOT NULL`。默认允许 `NULL` 值。 -## 主键约束 +## 唯一约束 -TiDB 支持的主键约束规则与 MySQL 支持的相似。例如: +在 TiDB 中,默认会对唯一约束进行[惰性检查](/transaction-overview.md#事务的惰性检查)。通过在事务提交时再进行批量检查,TiDB 能够减少网络开销、提升性能。例如: {{< copyable "sql" >}} ```sql -CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); -``` - -``` -Query OK, 0 rows affected (0.12 sec) +DROP TABLE IF EXISTS users; +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(60) NOT NULL, + UNIQUE KEY (username) +); +INSERT INTO users (username) VALUES ('dave'), ('sarah'), ('bill'); ``` {{< copyable "sql" >}} ```sql -CREATE TABLE t2 (a INT NULL PRIMARY KEY); +START TRANSACTION; ``` ``` -ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead +Query OK, 0 rows affected (0.00 sec) ``` {{< copyable "sql" >}} ```sql -CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY, b INT NOT NULL PRIMARY KEY); +INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); ``` ``` -ERROR 1068 (42000): Multiple primary key defined +Query OK, 3 rows affected (0.00 sec) +Records: 3 Duplicates: 0 Warnings: 0 ``` {{< copyable "sql" >}} ```sql -CREATE TABLE t4 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)); +INSERT INTO users (username) VALUES ('steve'),('elizabeth'); ``` ``` -Query OK, 0 rows affected (0.10 sec) +Query OK, 2 rows affected (0.00 sec) +Records: 2 Duplicates: 0 Warnings: 0 ``` -* 表 `t2` 创建失败,因为定义为主键的列 `a` 不能允许 `NULL` 值。 -* 表 `t3` 创建失败,因为一张表只能有一个主键。 -* 表 `t4` 创建成功,因为虽然只能有一个主键,但 TiDB 支持定义一个多列组合作为复合主键。 +{{< copyable "sql" >}} -除上述规则外,TiDB 还强加了另一个限制,即一旦一张表创建成功,其主键就不能再改变。 +```sql +COMMIT; +``` -## 唯一约束 +``` +ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' +``` -在 TiDB 中,默认会对唯一约束进行惰性检查。通过直到事务提交时才进行批量检查,TiDB 能够减少网络通信开销。例如: +* 第一条 `INSERT` 语句不会导致重复键错误,这同 MySQL 的规则一致。该检查将推迟到事务提交时才会进行。 -{{< copyable "sql" >}} +您可通过设置 `tidb_constraint_check_in_place` 为 `1` 停用此行为。如果停用此行为,则会在执行语句时就对唯一约束进行检查。例如: ```sql DROP TABLE IF EXISTS users; @@ -187,7 +133,7 @@ INSERT INTO users (username) VALUES ('dave'), ('sarah'), ('bill'); {{< copyable "sql" >}} ```sql -START TRANSACTION; +SET tidb_constraint_check_in_place = 1; ``` ``` @@ -197,78 +143,128 @@ Query OK, 0 rows affected (0.00 sec) {{< copyable "sql" >}} ```sql -INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); +START TRANSACTION; ``` ``` -Query OK, 3 rows affected (0.00 sec) -Records: 3 Duplicates: 0 Warnings: 0 +Query OK, 0 rows affected (0.00 sec) ``` {{< copyable "sql" >}} ```sql -INSERT INTO users (username) VALUES ('steve'),('elizabeth'); +INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); ``` ``` -Query OK, 2 rows affected (0.00 sec) -Records: 2 Duplicates: 0 Warnings: 0 +ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' +.. ``` +* 第一条 `INSERT` 语句导致了重复键错误。这会造成额外的网络通信开销,并可能降低插入操作的吞吐量。 + +## 主键约束 + +首先,与 MySQL 相同,主键约束包含了唯一约束,即创建了主键约束相当于拥有了唯一约束,此外,TiDB 其他的主键约束规则与 MySQL 相似。例如: + {{< copyable "sql" >}} ```sql -COMMIT; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); ``` ``` -ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' +Query OK, 0 rows affected (0.12 sec) ``` -* 第一条 `INSERT` 语句不会导致重复键错误,这同 MySQL 的规则一致。该检查将推迟到事务提交时才会进行。 - -如果将 `tidb_constraint_check_in_place` 更改为 `TRUE`,则会在执行语句时就对唯一约束进行检查。例如: +{{< copyable "sql" >}} ```sql -DROP TABLE IF EXISTS users; -CREATE TABLE users ( - id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, - username VARCHAR(60) NOT NULL, - UNIQUE KEY (username) -); -INSERT INTO users (username) VALUES ('dave'), ('sarah'), ('bill'); +CREATE TABLE t2 (a INT NULL PRIMARY KEY); +``` + +``` +ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead ``` {{< copyable "sql" >}} ```sql -SET tidb_constraint_check_in_place = TRUE; +CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY, b INT NOT NULL PRIMARY KEY); ``` ``` -Query OK, 0 rows affected (0.00 sec) +ERROR 1068 (42000): Multiple primary key defined ``` {{< copyable "sql" >}} ```sql -START TRANSACTION; +CREATE TABLE t4 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)); ``` ``` -Query OK, 0 rows affected (0.00 sec) +Query OK, 0 rows affected (0.10 sec) +``` + +* 表 `t2` 创建失败,因为定义为主键的列 `a` 不能允许 `NULL` 值。 +* 表 `t3` 创建失败,因为一张表只能有一个主键。 +* 表 `t4` 创建成功,因为虽然只能有一个主键,但 TiDB 支持定义一个多列组合作为复合主键。 + +除上述规则外,TiDB 还强加了另一个限制,即一旦一张表创建成功,其主键就不能再改变。 + +## 外键约束 + +TiDB 支持创建外键约束。例如: + +```sql +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + doc JSON +); +CREATE TABLE orders ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + user_id INT NOT NULL, + doc JSON, + FOREIGN KEY fk_user_id (user_id) REFERENCES users(id) +); ``` {{< copyable "sql" >}} ```sql -INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); +SELECT table_name, column_name, constraint_name, referenced_table_name, referenced_column_name +FROM information_schema.key_column_usage WHERE table_name IN ('users', 'orders'); ``` ``` -ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' -.. ++------------+-------------+-----------------+-----------------------+------------------------+ +| table_name | column_name | constraint_name | referenced_table_name | referenced_column_name | ++------------+-------------+-----------------+-----------------------+------------------------+ +| users | id | PRIMARY | NULL | NULL | +| orders | id | PRIMARY | NULL | NULL | +| orders | user_id | fk_user_id | users | id | ++------------+-------------+-----------------+-----------------------+------------------------+ +3 rows in set (0.00 sec) ``` -* 第一条 `INSERT` 语句导致了重复键错误。这会造成额外的网络通信开销,并可能降低插入操作的吞吐量。 +TiDB 也支持使用 `ALTER TABLE` 命令来删除外键(`DROP FOREIGN KEY`)和添加外键(`ADD FOREIGN KEY`): + +{{< copyable "sql" >}} + +```sql +ALTER TABLE orders DROP FOREIGN KEY fk_user_id; +ALTER TABLE orders ADD FOREIGN KEY fk_user_id (user_id) REFERENCES users(id); +``` + +### 注意 + +* TiDB 支持外键是为了在将其他数据库迁移到 TiDB 时,不会因为此语法报错。但是,TiDB 不会在 DML 语句中对外键进行约束检查。例如,即使 `users` 表中不存在 `id=123` 的记录,下列事务也能提交成功: + + ``` + START TRANSACTION; + INSERT INTO orders (user_id, doc) VALUES (123, NULL); + COMMIT; + ``` + +* TiDB 在执行 `SHOW CREATE TABLE` 语句的结果中不显示外键信息。 From fead2671320b509cab457058ff6c15a4ba4fcf48 Mon Sep 17 00:00:00 2001 From: Shuaipeng Yu Date: Wed, 20 May 2020 15:43:38 +0800 Subject: [PATCH 2/5] address comments Signed-off-by: Shuaipeng Yu --- constraints.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/constraints.md b/constraints.md index 809e45ee1967..2736187c440a 100644 --- a/constraints.md +++ b/constraints.md @@ -60,7 +60,7 @@ Query OK, 1 row affected (0.03 sec) ## 唯一约束 -在 TiDB 中,默认会对唯一约束进行[惰性检查](/transaction-overview.md#事务的惰性检查)。通过在事务提交时再进行批量检查,TiDB 能够减少网络开销、提升性能。例如: +在 TiDB 的乐观事务中,默认会对唯一约束进行[惰性检查](/transaction-overview.md#事务的惰性检查)。通过在事务提交时再进行批量检查,TiDB 能够减少网络开销、提升性能。例如: {{< copyable "sql" >}} @@ -118,7 +118,7 @@ ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' * 第一条 `INSERT` 语句不会导致重复键错误,这同 MySQL 的规则一致。该检查将推迟到事务提交时才会进行。 -您可通过设置 `tidb_constraint_check_in_place` 为 `1` 停用此行为。如果停用此行为,则会在执行语句时就对唯一约束进行检查。例如: +您可通过设置 `tidb_constraint_check_in_place` 为 `1` 停用此行为(该变量设置对悲观事务无效,悲观事务始终在语句执行时检查约束)。如果停用此行为,则会在执行语句时就对唯一约束进行检查。例如: ```sql DROP TABLE IF EXISTS users; From aa5c4244bc6e098fe95b2a65d3257030d0c1890d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 20 May 2020 15:45:44 +0800 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Keke Yi <40977455+yikeke@users.noreply.github.com> --- constraints.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/constraints.md b/constraints.md index 2736187c440a..999b86e2e3ea 100644 --- a/constraints.md +++ b/constraints.md @@ -116,7 +116,7 @@ COMMIT; ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' ``` -* 第一条 `INSERT` 语句不会导致重复键错误,这同 MySQL 的规则一致。该检查将推迟到事务提交时才会进行。 +第一条 `INSERT` 语句不会导致重复键错误,这同 MySQL 的规则一致。该检查将推迟到事务提交时才会进行。 您可通过设置 `tidb_constraint_check_in_place` 为 `1` 停用此行为(该变量设置对悲观事务无效,悲观事务始终在语句执行时检查约束)。如果停用此行为,则会在执行语句时就对唯一约束进行检查。例如: @@ -161,11 +161,11 @@ ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' .. ``` -* 第一条 `INSERT` 语句导致了重复键错误。这会造成额外的网络通信开销,并可能降低插入操作的吞吐量。 +第一条 `INSERT` 语句导致了重复键错误。这会造成额外的网络通信开销,并可能降低插入操作的吞吐量。 ## 主键约束 -首先,与 MySQL 相同,主键约束包含了唯一约束,即创建了主键约束相当于拥有了唯一约束,此外,TiDB 其他的主键约束规则与 MySQL 相似。例如: +与 MySQL 行为一样,主键约束包含了唯一约束,即创建了主键约束相当于拥有了唯一约束。此外,TiDB 其他的主键约束规则也与 MySQL 相似。例如: {{< copyable "sql" >}} @@ -207,6 +207,8 @@ CREATE TABLE t4 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)); Query OK, 0 rows affected (0.10 sec) ``` +分析: + * 表 `t2` 创建失败,因为定义为主键的列 `a` 不能允许 `NULL` 值。 * 表 `t3` 创建失败,因为一张表只能有一个主键。 * 表 `t4` 创建成功,因为虽然只能有一个主键,但 TiDB 支持定义一个多列组合作为复合主键。 From ad9eef7e2f4c8859258d6ec8a4adbdb0cf27eaec Mon Sep 17 00:00:00 2001 From: Shuaipeng Yu Date: Wed, 20 May 2020 16:31:28 +0800 Subject: [PATCH 4/5] address comments Signed-off-by: Shuaipeng Yu --- constraints.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/constraints.md b/constraints.md index 999b86e2e3ea..cf1b44ed968d 100644 --- a/constraints.md +++ b/constraints.md @@ -118,7 +118,7 @@ ERROR 1062 (23000): Duplicate entry 'bill' for key 'username' 第一条 `INSERT` 语句不会导致重复键错误,这同 MySQL 的规则一致。该检查将推迟到事务提交时才会进行。 -您可通过设置 `tidb_constraint_check_in_place` 为 `1` 停用此行为(该变量设置对悲观事务无效,悲观事务始终在语句执行时检查约束)。如果停用此行为,则会在执行语句时就对唯一约束进行检查。例如: +你可通过设置 `tidb_constraint_check_in_place` 为 `1` 停用此行为(该变量设置对悲观事务无效,悲观事务始终在语句执行时检查约束)。如果停用此行为,则会在执行语句时就对唯一约束进行检查。例如: ```sql DROP TABLE IF EXISTS users; @@ -217,6 +217,10 @@ Query OK, 0 rows affected (0.10 sec) ## 外键约束 +> **注意:** +> +> TiDB 仅部分支持外键约束功能。 + TiDB 支持创建外键约束。例如: ```sql From c4324ebaebf91705fbc9b9ca7bf91cc511349d4c Mon Sep 17 00:00:00 2001 From: Shuaipeng Yu Date: Sat, 23 May 2020 21:42:26 +0800 Subject: [PATCH 5/5] address comments Signed-off-by: Shuaipeng Yu --- constraints.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/constraints.md b/constraints.md index cf1b44ed968d..aae5e6717bb3 100644 --- a/constraints.md +++ b/constraints.md @@ -213,7 +213,9 @@ Query OK, 0 rows affected (0.10 sec) * 表 `t3` 创建失败,因为一张表只能有一个主键。 * 表 `t4` 创建成功,因为虽然只能有一个主键,但 TiDB 支持定义一个多列组合作为复合主键。 -除上述规则外,TiDB 还强加了另一个限制,即一旦一张表创建成功,其主键就不能再改变。 +除上述规则外,默认情况下,TiDB 还有一个额外限制,即一旦一张表创建成功,其主键就不能再改变。如果需要添加/删除主键,需要在 TiDB 配置文件中将 `alter-primary-key` 设置为 `true`,并重启 TiDB 实例使之生效。 + +当开启添加/删除主键功能以后,TiDB 允许对表添加/删除主键。但需要注意的是,对于在未开启该功能时创建的整数类型的主键的表,即使开启添加/删除主键功能,也不能删除其主键约束。 ## 外键约束