Skip to content

Commit

Permalink
constraints, create table: improve clarity and update out of date info (
Browse files Browse the repository at this point in the history
#4447) (#4584)

* cherry pick #4447 to release-3.1

Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

* resolve

* Update sql-statements/sql-statement-create-table.md

Co-authored-by: TomShawn <41534398+TomShawn@users.noreply.github.com>
  • Loading branch information
ti-srebot and TomShawn authored Sep 24, 2020
1 parent 2cd79a7 commit ac71055
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 196 deletions.
20 changes: 20 additions & 0 deletions constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,26 @@ Query OK, 0 rows affected (0.10 sec)

除上述规则外,TiDB 还强加了另一个限制,即一旦一张表创建成功,其主键就不能再改变。

## `CHECK` 约束

TiDB 会解析并忽略 `CHECK` 约束。该行为与 MySQL 5.7 的相兼容。

示例如下:

{{< 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),
CONSTRAINT min_username_length CHECK (CHARACTER_LENGTH(username) >=4)
);
INSERT INTO users (username) VALUES ('a');
SELECT * FROM users;
```

## 唯一约束

在 TiDB 中,默认会对唯一约束进行惰性检查。通过直到事务提交时才进行批量检查,TiDB 能够减少网络通信开销。例如:
Expand Down
256 changes: 60 additions & 196 deletions sql-statements/sql-statement-create-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ aliases: ['/docs-cn/v3.1/sql-statements/sql-statement-create-table/','/docs-cn/v

# CREATE TABLE

`CREATE TABLE` 语句用于在当前所选数据库中创建新表。另可参阅单独的 `CREATE TABLE LIKE` 文档。
`CREATE TABLE` 语句用于在当前所选数据库中创建新表,与 MySQL 中 `CREATE TABLE` 语句的行为类似。另可参阅单独的 `CREATE TABLE LIKE` 文档。

## 语法图

Expand Down Expand Up @@ -54,169 +54,12 @@ aliases: ['/docs-cn/v3.1/sql-statements/sql-statement-create-table/','/docs-cn/v

![TableOptionListOpt](/media/sqlgram/TableOptionListOpt.png)

## 语法说明

`CREATE TABLE` 用于创建一个表。目前不支持临时表,不支持 `CHECK` 约束,不支持创建表的同时从其它表导入数据功能。在语法上也支持一些 `Partition_options`,但是并不完全,就不做列举了。

以下是 `CREATE TABLE` 相关的语法说明:

{{< copyable "sql" >}}

```sql
CREATE TABLE [IF NOT EXISTS] tbl_name
(create_definition,...)
[table_options]
```

使用 `IF NOT EXIST` 时,即使创建的表已经存在,也不会报错,如果不指定时,则报错。

{{< copyable "sql" >}}

```sql
CREATE TABLE [IF NOT EXISTS] tbl_name
{ LIKE old_tbl_name | (LIKE old_tbl_name) }
```

使用 `LIKE` 基于一个表的定义创建一个空表,包括这个表中的列属性和索引属性。

```sql
create_definition:
col_name column_definition
| [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
[index_option] ...
| {INDEX|KEY} [index_name] [index_type] (index_col_name,...)
[index_option] ...
| [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY]
[index_name] [index_type] (index_col_name,...)
[index_option] ...
| {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...)
[index_option] ...
| [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name,...) reference_definition
```

`create_definition``FULLTEXT``FOREIGN KEY` 目前只是语法上支持。

```sql
column_definition:
data_type [NOT NULL | NULL] [DEFAULT default_value]
[AUTO_INCREMENT | AUTO_RANDOM [(length)]]
[UNIQUE [KEY] | [PRIMARY] KEY]
[COMMENT 'string']
[reference_definition]
| data_type [GENERATED ALWAYS] AS (expression)
[VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment]
[NOT NULL | NULL] [[PRIMARY] KEY]

data_type:
BIT[(length)]
| TINYINT[(length)] [UNSIGNED] [ZEROFILL]
| SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
| MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
| INT[(length)] [UNSIGNED] [ZEROFILL]
| INTEGER[(length)] [UNSIGNED] [ZEROFILL]
| BIGINT[(length)] [UNSIGNED] [ZEROFILL]
| REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
| DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
| FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
| DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL]
| NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL]
| DATE
| TIME[(fsp)]
| TIMESTAMP[(fsp)]
| DATETIME[(fsp)]
| YEAR
| CHAR[(length)] [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
| VARCHAR(length) [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
| BINARY[(length)]
| VARBINARY(length)
| TINYBLOB
| BLOB
| MEDIUMBLOB
| LONGBLOB
| TINYTEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
| TEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
| MEDIUMTEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
| LONGTEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
| ENUM(value1,value2,value3,...)
[CHARACTER SET charset_name] [COLLATE collation_name]
| SET(value1,value2,value3,...)
[CHARACTER SET charset_name] [COLLATE collation_name]
| JSON
```

`data_type` 请参考[数据类型](/data-type-overview.md)章节。

```sql
index_col_name:
col_name [(length)] [ASC | DESC]
```

`index_col_name``[ASC | DESC]` 目前只是语法上支持。

```sql
index_type:
USING {BTREE | HASH}
```

`index_type` 目前只是语法上支持。

```sql
index_option:
KEY_BLOCK_SIZE [=] value
| index_type
| COMMENT 'string'
```

`index_option``KEY_BLOCK_SIZE` 目前只是语法上支持。

```sql
reference_definition:
REFERENCES tbl_name (index_col_name,...)
[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
[ON DELETE reference_option]
[ON UPDATE reference_option]

reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
```

```sql
table_options:
table_option [[,] table_option] ...

table_option:
AUTO_INCREMENT [=] value
| AVG_ROW_LENGTH [=] value
| SHARD_ROW_ID_BITS [=] value
| PRE_SPLIT_REGIONS [=] value
| [DEFAULT] CHARACTER SET [=] charset_name
| CHECKSUM [=] {0 | 1}
| [DEFAULT] COLLATE [=] collation_name
| COMMENT [=] 'string'
| COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'}
| CONNECTION [=] 'connect_string'
| DELAY_KEY_WRITE [=] {0 | 1}
| ENGINE [=] engine_name
| KEY_BLOCK_SIZE [=] value
| MAX_ROWS [=] value
| MIN_ROWS [=] value
| ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
| STATS_PERSISTENT [=] {DEFAULT|0|1}
```

`table_option` 目前支持的只有 `AUTO_INCREMENT``SHARD_ROW_ID_BITS`(详情介绍请参考 [TiDB 专用系统变量和语法](/tidb-specific-system-variables.md#shard_row_id_bits))、`PRE_SPLIT_REGIONS``CHARACTER SET``COLLATE``COMMENT`,其它只是语法上支持。具体内容参考下表,各个子句之间用逗号隔开。
TiDB 支持以下 `table_option`。TiDB 会解析并忽略其他 `table_option` 参数,例如 `AVG_ROW_LENGTH``CHECKSUM``COMPRESSION``CONNECTION``DELAY_KEY_WRITE``ENGINE``KEY_BLOCK_SIZE``MAX_ROWS``MIN_ROWS``ROW_FORMAT``STATS_PERSISTENT`

| 参数 |含义 |举例 |
|----------------|--------------------------------------|----------------------------|
|`AUTO_INCREMENT`|自增字段初始值 |`AUTO_INCREMENT` = 5|
|`SHARD_ROW_ID_BITS`|用来设置隐式 _tidb_rowid 的分片数量的 bit 位数 |`SHARD_ROW_ID_BITS` = 4|
| `SHARD_ROW_ID_BITS` |用来设置隐式 _tidb_rowid 的分片数量的 bit 位数 |`SHARD_ROW_ID_BITS` = 4|
|`PRE_SPLIT_REGIONS`|用来在建表时预先均匀切分 `2^(PRE_SPLIT_REGIONS)` 个 Region |`PRE_SPLIT_REGIONS` = 4|
|`CHARACTER SET` |指定该表所使用的字符集 | `CHARACTER SET` = 'utf8mb4'|
|`COLLATE` |指定该表所使用的字符集排序规则 | `COLLATE` = 'utf8mb4_bin'|
Expand All @@ -226,79 +69,100 @@ table_option:

## 示例

创建一张简单表并插入一行数据:

{{< copyable "sql" >}}

```sql
CREATE TABLE t1 (a int);
DESC t1;
SHOW CREATE TABLE t1\G
INSERT INTO t1 (a) VALUES (1);
SELECT * FROM t1;
```

```
Query OK, 0 rows affected (0.11 sec)
```

{{< copyable "sql" >}}

```sql
CREATE TABLE t2 LIKE t1;
```
mysql> drop table if exists t1;
Query OK, 0 rows affected (0.23 sec)

```
Query OK, 0 rows affected (0.10 sec)
```
mysql> CREATE TABLE t1 (a int);
Query OK, 0 rows affected (0.09 sec)

{{< copyable "sql" >}}

```sql
DESC t1;
```

```
mysql> DESC t1;
+-------+---------+------+------+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+------+---------+-------+
| a | int(11) | YES | | NULL | |
+-------+---------+------+------+---------+-------+
1 row in set (0.00 sec)
```

{{< copyable "sql" >}}
mysql> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)

```sql
INSERT INTO t1 VALUES (1);
```
mysql> INSERT INTO t1 (a) VALUES (1);
Query OK, 1 row affected (0.03 sec)

mysql> SELECT * FROM t1;
+------+
| a |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
```
Query OK, 1 row affected (0.02 sec)
```

删除一张表。如果该表不存在,就建一张表:

{{< copyable "sql" >}}

```sql
SELECT * FROM t1;
DROP TABLE IF EXISTS t1;
CREATE TABLE IF NOT EXISTS t1 (
id BIGINT NOT NULL PRIMARY KEY auto_increment,
b VARCHAR(200) NOT NULL
);
DESC t1;
```

```
+------+
| a |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
```sql
mysql> DROP TABLE IF EXISTS t1;
Query OK, 0 rows affected (0.22 sec)
mysql> CREATE TABLE IF NOT EXISTS t1 (
-> id BIGINT NOT NULL PRIMARY KEY auto_increment,
-> b VARCHAR(200) NOT NULL
-> );
Query OK, 0 rows affected (0.08 sec)
mysql> DESC t1;
+-------+--------------+------+------+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+------+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| b | varchar(200) | NO | | NULL | |
+-------+--------------+------+------+---------+----------------+
2 rows in set (0.00 sec)
```

## MySQL 兼容性

* TiDB 不支持 `CREATE TEMPORARY TABLE` 语法。
* 支持除空间类型以外的所有数据类型。
* 不支持 `FULLTEXT``HASH``SPATIAL` 索引。
* `KEY_BLOCK_SIZE``ENGINE` 属性可被解析,但会被忽略。
* `index_col_name` 属性支持 length 选项,最大长度限制为 3072 字节。此长度限制不会更改,具体取决于存储引擎和建表时使用的字符集。
* `index_col_name` 属性支持 `ASC``DESC` 的索引排序选项。
* 为了与 MySQL 兼容,`index_col_name` 属性支持 length 选项,最大长度默认限制为 3072 字节。此长度限制可以通过配置项 `max-index-length` 更改,具体请参阅 [TiDB 配置文件描述](/tidb-configuration-file.md#max-index-length)
* 为了与 MySQL 兼容,TiDB 会解析但忽略 `index_col_name` 属性的 `[ASC | DESC]` 索引排序选项。
* `COMMENT` 属性最多支持 1024 个字符,不支持 `WITH PARSER` 选项。
* TiDB 在单个表中最多支持 512 列。InnoDB 中相应的数量限制为 1017,MySQL 中的硬限制为 4096。
* 当前仅支持 Range、Hash 和 Range Columns(单列)类型的分区表,详情参阅[分区表](/partitioned-table.md)
* TiDB 会解析并忽略 `CHECK` 约束,与 MySQL 5.7 相兼容。详情参阅 [`CHECK` 约束](/constraints.md#check-约束)
* TiDB 会解析并存储外键约束,但不会在 DML 语句中强制对外键进行约束检查。详情[外键约束](/constraints.md#外键约束)

## 另请参阅

* [数据类型](/data-type-overview.md)
* [DROP TABLE](/sql-statements/sql-statement-drop-table.md)
* [CREATE TABLE LIKE](/sql-statements/sql-statement-create-table-like.md)
* [SHOW CREATE TABLE](/sql-statements/sql-statement-show-create-table.md)

0 comments on commit ac71055

Please sign in to comment.