# TiDB技术分享

> 作者/来源: UCloud 运营管理员
> 发布时间: 2023-01-11T05:20:00.000Z
> 分类: 解决方案
> 标签: AI, 数据库, Java
> 原文链接: http://117.50.162.249:3000/yun/articles/1170

---

# TiDB技术分享

> 来源: https://www.ucloud.cn/yun/129680.html
> 作者: IT那活儿
> 发布日期: 发布于2023-01-11 13:20

TiDB技术分享

# **点击上方“IT那活儿”，关注后了解更多精彩内容！！**

前言

## **1. 目的**

本文档旨在为使用 TiDB 数据库的应用和系统提供统一规范参考，标准化 TiDB 数据库 的开发使用及SQL优化流程，提高业务开发系统的规范性和代码的可读性，减轻维护工作量， 提高工作效率。

## **2. 适用范围**

● TiDB 数据库开发设计人员

● 数据库管理人员

● 数据库运营人员

● 数据分析人员

● 数据库架构师

## **3. 注意事项**

TiDB 暂时不支持的特性：

● 存储过程

● 触发器

● 自定义函数

● 外键约束

● 全文索引

● 空间索引

● 非 UTF8 字符集

对象命名规范

用于规范数据库对象的名命，如数据库（DATABASE）、表（TABLE）、索引（INDEX）、用户（USER）等的命名约定。

## **1. 原则**

1）命名建议使用具有意义的英文词汇，词汇中间以下划线分隔；

2）命名只能使用英文字母、数字、下划线；

3）避免用 TiDB 的保留字如：group，order 等作为单个字段名；

4）建议所有数据库对象使用小写字母。

## **2. 数据库命名规范**

建议按照业务、产品线或者其它指标进行区分，一般不要超过 20 个字符。如：临时库（ db\_tmp）、测试库（db\_test）。

## **3. 表**

### **3.1. 表命名规范**

1）同一业务或者模块的表尽可能使用相同的前缀，表名称尽可能表达含义。

2）多个单词以下划线分隔，不推荐超过32个字符。

3）建议对表的用途进行注释说明，以便于统一认识。如：

● 临时表（tbl\_tmp\_crm\_relation\_0425）；

● 备份表（tbl\_bak\_crm\_relation\_20170425）。

4）不同业务模块的表多带带建立 DATABASE，并增加相应注释。

5）目前 TiDB 只支持将 lower-case-table-names 值设为 2，即按照大小写来保存表名，按照小 写来比较（不区分大小写）。

### **3.2. 表的设计**

1）在进行 TiDB 表设计过程中，有以下几点需要注意：

● 为了保障主从集群复制以及增量备份的幂等性，表需要有主键。建议采用自然主键，而非业务字段作为主键。TIDB为避免热点问题，可以用AutoRandom替换AUTOINCREMENT，随机分配，采用unsigned bigint 作为该列的列属性。

建议采用聚簇索引，非聚簇索引主键实际为唯一索引，存储仍以隐式的rowid构成。聚簇索引不支持增删改操作。

● 出于为性能考虑，尽量避免存储超宽表，表字段数不建议超过 60 个，建议单行的总数 据大小不要超过 64K，数据长度过大字段最好拆到另外的表。

● 表及字段要加commet属性，方便业务的理解。

● 单表数据规模建议在1000万以内。对于大型业务表，建议建表初期设计分区以及清理备份策略。

● 需要 join 的字段，数据类型保障绝对一致，避免隐式转换。

● 字段属性尽量加上NOT NULL约束以及默认值，使用NULL值会导致如下副作用：

----含义不明，对很多运算符不管用，增加复杂度。

----很难进行查询优化。

----含NULL的复合索引失效。

2）TiDB 字符集默认就是 UTF8 ，而且目前只支持 UTF8：

● 使用 utf8mb4 编码，它是 utf8 的超集，除了将编码改为 utf8mb4 外不需要做其他转换。

● TiDB 中，utf8mb4 的默认排序规则为 utf8mb4\_bin（区分大小写）。

● 4.0 支持 utf8mb4\_general\_ci（不区分大小写） ，需要初始化集群前配置 new\_collations\_enabled\_on\_first\_bootstrap = true 。

## **4. 字段**

### **4.1. 字段命名规范**

1）字段命名需要表示其实际含义的英文单词或简写；

2）建议各表之间相同意义的字段应同名；

3）字段需要添加注释，枚举型需指明主要值的含义，如”0 - 离线，1 - 在线”；

4）布尔值列命名为 [is\_描述]。如 member 表上表示为 enabled 的会员的列命名为 is\_enabled ；

5）字段名不建议超过 30 个字符，字段个数不建议大于 60；

6）尽量避免使用保留字，如 order、from、desc 等，请参考官方保留字。

### **4.2. 字段的设计**

1）整数类型

● TiDB 支持 MySQL 所有的整数类型，包括 INTEGER/INT、TINYINT、SMALLIN、T MEDIUMINT 以及 BIGINT；

● INT：所有整数类型的字段推荐只使用 INT 或者 BIGINT；

● BIGINT：定义中不推荐添加长度；

● 推荐使用 INT(10) UNSIGNED 存储 IPv4 格式 IP 地址；

● TINYINT(1)、TINYINT(4) 都是存储一个字节，并不会因为括号里的数字改变。例如 TINYINT(4) 存储 22 则会显示 0022，因为最大宽度为4，达不到的情况下用0来补充。

2）浮点类型

● TiDB 支持 MySQL 所有的浮点类型，包括 FLOAT、DOUBLE，DECIMAL、NUMERIC 等。

● DECIMAL(M,D)：推荐使用 DECIMAL 类型。float 和 double 在存储的时候，存在精度 损失的问题，很可能在值的比较时，得到不正确的结果。DECIMAL 在与 VARCHAR、 CHAR 类型比较时会转换为 DOUBLE 类型进行比较，也存在精度损失问题，建议在进 行比较时使用显示类型转换，如 CAST 避免精度损失。

3）日期时间类型

● TiDB 支持 MySQL 所有的日期时间类型，包括 DATE、DATETIME、TIMESTAM、P TIME 以及 YEAR；

● DATE：所有只需要精确到天的字段全部使用 DATE 类型，而不应该使用 TIMESTAMP 或者DATETIME 类型；

● DATETIME：所有需要精确到时间(时分秒)的字段均使用 DATETIME，不要使用 TIMESTAMP 类型；

● 时间字段使用时间日期类型，不要使用字符串类型存储。否则无法利用日期函数对日 期字段进行操作，而需要使用字符串函数进行复杂的操作。

4）处理日期和时间类型时，请记住下面这些：

● 尽管 TiDB 尝试解释不同的格式，日期部分必须是按 年-月-日 的顺序（比如，’ 98-09-04’），而不是 月-日-年 或者 日-月-年 的顺序；

● 要求年份必须是四位数字。日期值中包含两位数字的年份是有歧义的，TiDB 按下面规则解释：范围在 70-99 之间的被转换成 1970-1999 范围在 00-69 之间的被转换成 2000-2069 。

5）字符串类型

● TiDB 支持 MySQL 所有的字符串类型，包括 CHAR、VARCHAR、BINARY、 VARBINARY、BLOB、TEXT、ENUM 以及 SET；

● VARCHAR(N)：所有动态长度字符串全部使用 VARCHAR 类型，N 表示的是字符数不 是字节数，比如 VARCHAR(256)，需要根据实际的宽度来选择 N，N 尽可能小；

● CHAR：仅仅只有单个字符的字段使用 CHAR(1) 类型，例如性别字段；

● TEXT：仅仅当字符数量可能超过 20000 个的时候，才建议使用TEXT类型来存放字符 类数据，因为所有 TiDB 数据库都会使用 UTF8 字符集。所有使用 TEXT 类型的字段 建议和原表进行分拆，与原表主键多带带组成另外一个表进行存放；

● 不建议使用 ENUM、SET 类型，尽量使用 TINYINT 来代替。

## **5. 索引**

### **5.1. 索引命名规范**

#### 1）主键索引：

pk\_[表名称简写]\_[字段名简写]。

#### 2）唯一索引：

uk\_[表名称简写]\_[字段名简写]。

#### 3）普通索引：

idx\_[表名称简写]\_[字段名简写] 4）多单词组成的 column\_name，取尽可能代表意义的缩写。

### **5.2. 索引设计**

1）选择区分度大的列建立索引，不在低基数列上建立索引，例如：“性别”，“是否是 XXX”；

2）单张表的索引数量控制在 5 个以内，避免冗余索引；

3）索引中的字段数建议不超过 5 个；

4）唯一索引建议由 3 个或更少的字段组成；

5）尽量不要在频繁更新的列上创建索引；

6）对于确定需要组成组合索引的多个字段，建议将选择性高的字段靠前放；

7）最左前缀原则，使用联合索引时，从左向右匹配，比如索引 idx\_c1\_c2\_c3 (c1,c2,c3，)相当 于创建了 (c1)、(c1,c2)、(c1,c2,c3) 三个索引，where 条件包含上面三种情况的字段比较则可 以用到索引，但像 where c1=a and c3=c 只能用到 c1 列的索引，像 c2=b and c3=c 等情况就 完全用不到这个索引；

8）很长的 VARCHAR 字段建立索引时，指定索引长度，没必要对全字段建立索引，根据 实际 文本区分度决定索引长度即可。idx\_table\_name (name(10))；

9）定期删除一些长时间未使用过的索引；

10）ORDER BY，GROUP BY，DISTINCT 的字段需要添加在索引的后面，形成覆盖索引；

11）不建议在 where 条件索引列上使用函数，会导致索引失效，如 lower(email)；

12）使用 like 模糊匹配，% 不要放首位，会导致索引失效。

### **5.3. TiDB 中的索引**

索引也是数据，也要占用存储空间。和表中的数据一样，TiDB 中表的索引在存储引擎 中也被作为 kv 来存储，一行索引是一个 kv 对。例如一张有 10 个索引的表，每插入一行数据 的时候，会写入 11 个 kv 对。

TiDB 支持主键索引，唯一索引，也支持二级索引，构成以上索引的可以是单一列，也 可以是多个列（复合索引）。TiDB 目前（v5.0）还不支持反向/双向索引，全文索引，分区表的全局索引。

TiDB 中在查询的谓词是 =，>，=，<=，like ‘...%’，not like ‘.，..i%n，’ not in，<>，!=， is null，is not null，between…and … 时能够使用索引，使用与否由优化器来决策。TiDB 中在查询的谓词是 like ‘%...’，like ‘%...%’，not like ‘%..，.’not like ‘%...%’，<=> 时 ，都无法使用索引。目前版本（v5.0）还没有对 <=> 做处理，无法像 is null 一样使用索引。

数据库对象设计

## **1. 账号权限**

TiDB 在数据库初始化时会生成一个 root@% 的默认账户，生产环境建议调整 root 用户为强密码，且不对外开放。线上所需用户建议按照用户或者业务场景划分，根据实际情况对每个用户授予相应权限，例如：

|  |  |  |  |
| --- | --- | --- | --- |
| 1 | root | 超级用户 | 全局管理，禁止对外开放 |
| 2 | dba | 数据库管理员 | 数据库 DBA |
| 3 | app | 应用开发 | 应用开发 |
| 4 | tempuser | 临时统计 | 线上业务临时统计，只读用户 |
| 5 | other | 其他用户 | 第三方人员访问 |

**2. 角色**

## 

角色是一系列权限的集合。用户可以创建角色、删除角色、将权限赋予角色；也可以将角色授予给其他用户，被授予的用户在启用角色后，可以得到角色所包含的权限。

### **2.1. 创建角色**

```
CREATE ROLE app_developer, app_read, app_write;
```

角色会被保存在 mysql.user 表中，角色名称的主机名部分（如果省略）默认为 %。如果表中有同名角色或用户，角色会创建失败并报错。创建角色的用户需要拥有 CREATE ROLE 或 CREATE USER 权限。

### **2.2. 角色授权**

为 app\_read 角色授予数据库 app\_db 的读权限：

```
GRANT SELECT ON app_db.* TO app_read@%;
```

### **2.3. 角色赋给用户**

使用 GRANT 授予用户对应的角色。

```
GRANT app_read TO dev1@localhost;
```

### **2.4. 默认角色**

角色在授予给用户之后，并不会生效；只有在用户启用了某些角色之后，才可以使用角色拥有的权限。

可以对用户设置默认启用的角色；用户在登录时，默认启用的角色会被自动启用。

比如将 app\_read 和 app\_wirte 设置为 rw\_user1@localhost 的默认启用角色：

```
SET DEFAULT ROLE app_read, app_write TO rw_user1@localhost;
```

将 dev1@localhost 的所有角色，设为其默认启用角色：

```
SET DEFAULT ROLE ALL TO dev1@localhost;
```

### **2.5. 启用角色**

为当前用户启用角色 app\_read 和 app\_write ，仅在当前 session 有效：

```
SET ROLE app_read, app_write;
```

启用当前用户的默认角色：

```
SET ROLE DEFAULT
```

启用授予给当前用户的所有角色：

```
SET ROLE ALL
```

不启用任何角色：

```
SET ROLE NONE
```

启用除 app\_read 外的角色：

```
SET ROLE ALL EXCEPT app_read
```

SQL 开发规范

## **1. 建表删表规范**

1.1. 基本原则：表的建立在遵循表命名规范前提下，建议业务应用内部封装建表删表语句增加判断逻辑，防止业务流程异常中断。

1.2. 详细说明：create table if not exists table\_name 或 者 drop table if exists table\_name 语句建议增加 if 判 断，避免应用侧由于表的改动造成的异常中断。

1.3. 不支持 create table as select 语法，需要改写为表结构复制 create table like … 和将数据写入的 insert into select … 的组合语句。

## **2. select \* 使用规范**

2.1. 基本原则：禁止使用 select \* 进行查询。

2.2. 详细说明：按需求选择合适的字段列，杜绝直接 SELECT \* 读取全部字段，减少网络带宽消耗，有效利用 覆盖索引。

## **3. Region 热点**

region 热点可能的原因：

● 这条 SQL 涉及到的 region 的 leader 全部在这个 TiKV 上；

● 这条 SQL 只涉及到一个 region，并且有大量的请求使用同样或者类似的 SQL。

3.1. 基本原则：如果表的数据量比较小，数据存储大概率只涉及到一个 region，大量请求对该表进行写入或者读取都会造成该 region 热点，可以通过手工拆分 region 方式进行调整，也可以在建表时预先进行 split region。

3.2. 详细说明：如何有效避免热点？

●Handle ID 设计 避免连续自增主键的设计，建议采用AutoRandom替换AUTOINCREMENT，随机分配；

● TiDB Partition 通过设置表分区方式来避免热点，支持按照 Hash 以及按照 Range 分区。

## **4. 字段上使用函数规范**

4.1. 基本原则：在取出字段上可以使用相关函数,但是在 Where 条件中的过滤条件字段上严禁使用任何函数, 包括数据类型转换函数。

4.2. 详细说明：

● 错误的写法：

```
``` select gmt_create from ... where date_format(gmt_create，%Y%m%d %H:%i:%s) = 20090101 00:00:0 ```
```

● 正确的写法：

```
``` select date_format(gmt_create，%Y%m%d %H:%i:%s) from .. . where gmt_create = str_to_date(20090101 00:00:00，%Y%m%d %H:%i:s)；```
```

## **5. 数据删除规范**

5.1. 基本原则：

删除表中全部的数据时，使用 TRUNCATE 或者 DROP 后重建方式，不要使用 DELETE；

5.2. 详细说明：

DELETE，TRUNCATE 和 DROP 都不会立即释放空间，对于 TRUNCATE 和 DROP操作，在 达到 TiDB 的 GC (garbage collection) 时间后（默认 10 分钟），TiDB的 GC 机制会删除数据 并释放空间。对于 DELETE 操作 TiDB 的 GC 机制会删除数据，但不会释放空间，而是当后 续数据写入 RocksDB 且进行 compact 时对空间重新利用。

隔离级别

TiDB 支持的隔离级别是 Snapshot Isolation（SI），和 RepeatabRleead（RR） 隔离级别 基本等价。

大事务限制

基于日志的数据库在面对大事务时，需要手动调大可用日志的容量，以避免日志被单 一事务占满。TiDB 处理大事务的性能相较于处理并发的小事务的性能要差，因此 TiDB 中对于事务 量设定了一些限制：

● 最大单行记录容量为 120MB（v5.0 及更高的版本可通过 tidb-server 配置项 performance.txn-entry-size-limit 调整，低于 v5.0 的版本支持的单行容量为 6MB）；

● 支持的最大单个事务容量为 10GB（v4.0 及更高版本可通过 tidb-server 配置项 performance.txn-total-size-limit 调整，低于 v4.0 的版本支持的最大单个事务容量为 100MB）。

结果集不稳定

## **1. group by**

出于便捷的考量，MySQL “扩展” 了 group by 语法，使 select 子句可以引用未在 group by 子句中声明的非聚集字段，也就是 non-full group by 语法，在其他数据库中，这被认为是一种语法错误，因为这会导致结果集不稳定。想保障 group by 语句结果集的稳定，请使用 full group by 语法。

## **2. order by**

在 SQL 的语义中，只有使用了 order by 语法才会保障结果集的顺序输出。而单机数据 库由于数据都存储在一台服务器上，在不进行数据重组时，多次执行的结果往往是稳定的，有些数据库(尤其是 MySQL InnoDB 存储引擎)还会按照主键或索引的顺序进行结果集的输出。TiDB 是分布式数据库，数据被存储在多台服务器上，另外 TiDB 层不缓存数据页，因此不含 order by 的 SQL 语句的结果集展现顺序容易被感知到不稳定。想要按顺序输出的结果集，需 明确的把要排序的字段添加到 order by 子句中，这符合 SQL 的语义。

TiDB 中的各种超时

## **1. GC 超时**

TiDB的事务的实现采用了 MVCC（多版本并发控制）机制，当新写入的数据覆盖旧的数据时，旧的数据不会被替换掉，而是与新写入的数据同时保留，并以时间戳来区分版本。TiDB 通过定期 GC 的机制来清理不再需要的旧数据。默认配置下 TiDB 可以保障每个 MVCC 版本（一致性快照）保存 10 分钟，读取时间超 过 10 分钟的事务，会收到报错GC life time is shorter than transaction duration 当用户确信自己需要更长的读取时间时，比如在使用了 Mydumper 做全量备份的场景 中（Mydumper 备份的是一致性的快照），可以通过调整 TiDB 中 mysql.tidb 表中的 tikv\_gc\_life\_time 的值来调大 MVCC 版本保留时间，需要注意的是 tikv\_gc\_life\_time 的配置是立刻影响全局的，调大它会为当前所有存在的快照增加生命时长，调小它会立即缩短所有快照的生命时长。过多的 MVCC 版本会拖慢 TiKV 的处理效率，在使用 Mydumper 做完全量备份 后需要及时把 tikv\_gc\_life\_time 调整回之前的设置。

## **2. 事务超时**

含 DML 语句的事务，除了受tikv\_gc\_life\_time 限制之外，还受到另外一个参数 max-txn-time-use 的影响，这个参数位于 tidb-server 的配置文件 tidb.toml 中，用于控制单个事 务允许的最大执行时间。该参数的默认值为 590（秒），需要注意必须控制该参数的值小于 tikv\_gc\_life\_time 的值。形如 insert into t10 select \* from t1 的 SQL 语句，即使执行时间没有达到 tikv\_gc\_life\_time 限制，但超过了 max-txn-time-use 的限制，会由于超时而回滚。

## **3. SQL 超时**

TiDB 还提供了一个系统变量来限制单条 SQL 语句的执行时间：max\_execution\_time， 它的默认值为 0，表示无限制。max\_execution\_time 目前对所有类型的 statement 生效，并非只 对 SELECT 语句生效。其单位为 ms，但实际精度在 100ms 级别，而非更准确的毫秒级别。

MySQL Connector/J 推荐版本

## **1. TiDB 服务端兼容**

TiDB 服务端兼容 MySQL 5.7，客户端推荐使用 5.1.36 或更高版本 的 5.1.x jdbc 驱动。

## **2. JDBC 参数设置**

Java 应用常用的数据库连接池包括 weblogic、c3p0、Druid等。使用连接池配置数据源 时，需要配置一系列参数，其中比较重要的包括 jdbc 的 url 配置，超时探活机制等。充分认识并理解各项参数有助于让 TiDB 发挥出更高的性能。

一个建议的 url 配置如下：

```
spring.datasource.url=JDBC:mysql://{TiDBIP}:{TiDBPort}/{DBName}?characterEncoding= utf8&useSSL=false&useServerPrepStmts=true&prepStmtCacheSqlLimit=10000000000&useCon figs=maxPerformance&rewriteBatchedStatements=true&defaultfetchsize=-214783648
```

序列（Sequence）

序列是一种数据库对象，应用程序通过调用某个序列可以产生递增的序列值，应用程序可以灵活的使用这个序列值为一张表或多张表赋值，也可以使用序列值进行更复杂的加工，来实现文本和数字的组合，来赋予代理键以一定的跟踪和分类的意义。TiDB 从 v4.0 版本开 始提供序列功能，详情请参考官方文档。

语法：

```
CREATE [TEMPORARY] SEQUENCE [IF NOT EXISTS] sequence_name[ INCREMENT [ BY | = ] increment ][ MINVALUE [=] minvalue | NO MINVALUE | NOMINVALUE ][ MAXVALUE [=] maxvalue | NO MAXVALUE | NOMAXVALUE ][ START [ WITH | = ] start ][ CACHE [=] cache | NOCACHE | NO CACHE][ CYCLE | NOCYCLE | NO CYCLE][ ORDER | NOORDER | NO ORDER][table_options]
```

|  |  |  |
| --- | --- | --- |
| 参数 | 默认值 | 描述 |
| TEMPORARY | FALSE | TiDB 暂时不支持 TEMPORARY 选项，仅在语法上做兼容。 |
| INCREMENT | 1 | 指定序列的步长。其正负值可以控制序列的增长方向。 |
| MINVALUE | 1 或 -9223372036854775807 | 指定序列的最小值。当 INCREMENT > 0 时，默认值为 1；当 INCREMENT < 0 时，默认值为 -9223372036854775807。 |
| MAXVALUE | 9223372036854775806 或 -1 | 指定序列的最大值。当 INCREMENT > 0 时，默认值为 9223372036854775806；当 INCREMENT < 0 时，默认值为 -1。 |
| START | MINVALUE 或 MAXVALUE | 指定序列的初始值。当 INCREMENT > 0 时，默认值为 MINVALUE; 当 INCREMENT < 0 时，默认值为 MAXVALUE。 |
| CACHE | 1000 | 指定每个 TiDB 本地缓存序列的大小。 |
| CYCLE | NO CYCLE | 指定序列用完之后是否要循环使用。在 CYCLE 的情况下，当 INCREMENT > 0 时，序列用完后的后续起始值为 MINVALUE；当 INCREMENT < 0 时，序列用完后的后续起始值为 MAXVALUE。 |
| ORDER | NO ORDER | TiDB 暂时不支持 ORDER 选项，仅在语法上做兼容。 |

## **1. SEQUENCE函数**

主要通过表达式函数来操纵序列的使用。

**● NEXTVAL 或 NEXT VALUE FOR**

本质上都是 nextval() 函数，获取序列对象的下一个有效值，其参数为序列的 identifier。

**● LASTVAL**

lastval() 函数，用于获取本会话上一个使用过的值。如果没有值，则为 NULL，其参数为序列的 identifier。

**● SETVAL**

setval() 函数，用于设置序列的增长。其第一参数为序列的 identifier，第二个参数为 num。

## **2. 示例**

### **2.1. 创建一个默认参数的序列对象**

```
CREATE SEQUENCE seq;Query OK, 0 rows affected (0.06 sec)
```

### **2.2. 使用 nextval() 函数获取序列对象的下一个值**

```
SELECT nextval(seq);+--------------+| nextval(seq) |+--------------+| 1 |+--------------+1 row in set (0.02 sec)
```

### **2.3. 使用 lastval() 函数获取本会话上一次调用序列对象所产生的值**

```
SELECT lastval(seq);+--------------+| lastval(seq) |+--------------+| 1 |+--------------+ row in set (0.02 sec)
```

### **2.4. 使用 setval() 函数设置序列对象当前值的位置**

```
SELECT setval(seq, 10);+-----------------+| setval(seq, 10) |+-----------------+| 10 |+-----------------+1 row in set (0.01 sec)
```

### **2.5. 使用 next value for 语法获取序列的下一个值**

```
SELECT next value for seq;+--------------------+| next value for seq |+--------------------+| 11 |+--------------------+1 row in set (0.00 sec)
```

其他操作

## **1. ADD COLUMN**

ALTER TABLE.. ADD COLUMN 语句用于在已有表中添加列。在 TiDB 中，ADD COLUMN 为在线操作，不会阻塞表中的数据读写。

● 不支持在一条语句中同时添加多列；

● 不支持将新添加的列设为 PRIMARY KEY；

● 不支持将新添加的列设为 AUTO\_INCREMENT。

## **2. ADD INDEX**

ALTER TABLE.. ADD INDEX 语句用于在已有表中添加一个索引。在 TiDB 中，ADD INDEX 为在线操作，不会阻塞表中的数据读写。

● 不支持 FULLTEXT，HASH 和 SPATIAL 索引；

● 不支持降序索引（类似于 MySQL 5.7）；

● 目前尚不支持在一条中同时添加多个索引；

● 无法向表中添加 CLUSTERED 类型的 PRIMARY KEY。

## **3. ALTER TABLE**

**3.1 ALTER TABLE 语句用于对已有表进行修改，以符合新表结构。ALTER TABLE 语句可用于：**

●  ADD，DROP，或 RENAME 索引；

●  ADD，DROP，MODIFY 或 CHANGE 列。

**3.2 TiDB 中的 ALTER TABLE 语法主要存在以下限制：**

● 不支持在单个 ALTER TABLE 语句中进行多个更改；

● 不支持主键列上 Reorg-Data 类型的变更；

● 不支持分区表上的列类型变更；

● 不支持生成列上的列类型变更；

● 不支持部分数据类型（例如，部分时间类型、Bit、Set、Enum、JSON 等）的变更，因为 TiDB 中的 CAST 函数与 MySQL 的行为存在兼容性问题；

● 不支持空间数据类型。

## **4. ALTER INDEX**

ALTER INDEX 语句用于修改索引的可见性，可以将索引设置为 Visible 或者 Invisible。设置为 Invisible 的索引即不可见索引 (Invisible Index) 由 DML 语句维护，不会被查询优化器使用。

## **5. CHANGE COLUMN**

ALTER TABLE.. CHANGE COLUMN 语句用于在已有表上更改列，包括对列进行重命名，和将数据改为兼容类型。

从 v5.1.0 版本起，TiDB 开始支持 Reorg 数据的类型变更，包括但不限于：

● 从 varchar 转换为 bigint；

● decimal 精度修改；

● 从 varchar(10) 到 varchar(5) 的长度压缩。

## **6. MySQL 兼容性**

● 不支持在单个 ALTER TABLE 语句中进行多个更改；

●不支持主键列上 [Reorg-Data](/sql-statements/sql-statement-modify-column.md#Reorg-Data Change) 类型的变更；

● 不支持分区表上的列类型变更；

● 不支持生成列上的列类型变更；

● 不支持部分数据类型（例如，部分时间类型、Bit、Set、Enum、JSON 等）的变更，因为TiDB 中 CAST 函数与 MySQL 的行为存在兼容性问题。

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129680/images/129680_000.png)

## 本 文 原 创 来 源：IT那活儿微信公众号（上海新炬王翦团队）

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129680/images/129680_001.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129680/images/129680_002.png)