- 关于 TiDB
- 主要概念
- 操作指南
- 快速上手
- 部署
- 配置
- 安全
- 安全传输层协议 (TLS)
- 生成自签名证书
- 监控
- 迁移
- 运维
- 扩容缩容
- 升级
- 故障诊断
- 参考手册
- SQL
- 与 MySQL 兼容性对比
- SQL 语言结构
- 数据类型
- 函数与操作符
- SQL 语句
ADD COLUMN
ADD INDEX
ADMIN
ADMIN CANCEL DDL
ADMIN CHECKSUM TABLE
ADMIN CHECK [TABLE|INDEX]
ADMIN SHOW DDL [JOBS|QUERIES]
ALTER DATABASE
ALTER TABLE
ALTER USER
ANALYZE TABLE
BEGIN
CHANGE COLUMN
COMMIT
CREATE DATABASE
CREATE INDEX
CREATE ROLE
CREATE TABLE LIKE
CREATE TABLE
CREATE USER
CREATE VIEW
DEALLOCATE
DELETE
DESC
DESCRIBE
DO
DROP COLUMN
DROP DATABASE
DROP INDEX
DROP ROLE
DROP TABLE
DROP USER
DROP VIEW
EXECUTE
EXPLAIN ANALYZE
EXPLAIN
FLUSH PRIVILEGES
FLUSH STATUS
FLUSH TABLES
GRANT <privileges>
GRANT <role>
INSERT
KILL [TIDB]
LOAD DATA
LOAD STATS
MODIFY COLUMN
PREPARE
RECOVER TABLE
RENAME INDEX
RENAME TABLE
REPLACE
REVOKE <privileges>
REVOKE <role>
ROLLBACK
SELECT
SET DEFAULT ROLE
SET [NAMES|CHARACTER SET]
SET PASSWORD
SET ROLE
SET TRANSACTION
SET [GLOBAL|SESSION] <variable>
SHOW ANALYZE STATUS
SHOW CHARACTER SET
SHOW COLLATION
SHOW [FULL] COLUMNS FROM
SHOW CREATE TABLE
SHOW CREATE USER
SHOW DATABASES
SHOW ENGINES
SHOW ERRORS
SHOW [FULL] FIELDS FROM
SHOW GRANTS
SHOW INDEXES [FROM|IN]
SHOW INDEX [FROM|IN]
SHOW KEYS [FROM|IN]
SHOW PRIVILEGES
SHOW [FULL] PROCESSSLIST
SHOW SCHEMAS
SHOW STATUS
SHOW [FULL] TABLES
SHOW TABLE REGIONS
SHOW TABLE STATUS
SHOW [GLOBAL|SESSION] VARIABLES
SHOW WARNINGS
SPLIT REGION
START TRANSACTION
TRACE
TRUNCATE
UPDATE
USE
- 约束
- 生成列
- 分区表
- 字符集
- SQL 模式
- 视图
- 配置
- tidb-server
- pd-server
- tikv-server
- 安全
- 事务
- 系统数据库
- 错误码
- 支持的连接器和 API
- 垃圾回收 (GC)
- 性能调优
- 监控指标
- 报警规则
- 最佳实践
- TiSpark 使用指南
- TiKV
- TiDB Binlog
- 工具
- TiDB in Kubernetes
- 常见问题 (FAQ)
- 技术支持
- 贡献
- 版本发布历史
- 发布版本汇总
- v3.0
- v2.1
- v2.0
- v1.0
- 术语表
你正在查看 TiDB 数据库的较旧版本 (TiDB v3.0) 的文档。
TiDB 事务概览
TiDB 支持完整的分布式事务,提供乐观事务与悲观事务(TiDB 3.0 中引入)两种事务模型。本文主要介绍涉及到事务的语句、显式/隐式事务、事务的隔离级别和惰性检查,以及事务大小的限制。
常用的变量包括 autocommit
、tidb_disable_txn_auto_retry
以及 tidb_retry_limit
。
变量 tidb_disable_txn_auto_retry
和 tidb_retry_limit
仅适用于乐观事务,不适用于悲观事务。
常用事务语句
BEGIN
和 START TRANSACTION
语法:
BEGIN;
START TRANSACTION;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
以上三条语句都用于开启事务,效果相同。执行开启事务语句可以显式地开启一个新的事务。如果执行以上语句时,当前 Session 正处于一个事务的中间过程,那么系统会先自动提交当前事务,再开启一个新的事务。
COMMIT
语法:
COMMIT;
该语句用于提交当前的事务,包括从 [BEGIN|START TRANSACTION]
到 COMMIT
之间的所有修改。
ROLLBACK
语法:
ROLLBACK;
该语句用于回滚当前事务,撤销从 [BEGIN|START TRANSACTION]
到 ROLLBACK
之间的所有修改。
自动提交
语法:
SET autocommit = {0 | 1}
当 autocommit = 1
时(默认),当前的 Session 为自动提交状态,即每条语句运行后,TiDB 会自动将修改提交到数据库中。设置 autocommit = 0
时更改当前 Session 更改为非自动提交状态,通过执行 COMMIT
语句来手动提交事务。
某些语句执行后会导致隐式提交。例如,执行 [BEGIN|START TRANCATION]
语句时,TiDB 会试图提交上一个事务,并开启一个新的事务。详情参见 implicit commit。
另外,autocommit
也是一个系统变量,你可以通过变量赋值语句修改当前 Session 或 Global 的值。
SET @@SESSION.autocommit = {0 | 1};
SET @@GLOBAL.autocommit = {0 | 1};
显式事务和隐式事务
TiDB 可以显式地使用事务(通过 [BEGIN|START TRANSACTION]
/COMMIT
语句定义事务的开始和结束) 或者隐式地使用事务 (SET autocommit = 1
)。
在自动提交状态下,使用 [BEGIN|START TRANSACTION]
语句会显式地开启一个事务,同时也会禁用自动提交,使隐式事务变成显式事务。直到执行 COMMIT
或 ROLLBACK
语句时才会恢复到此前默认的自动提交状态。
对于 DDL 语句,会自动提交并且不能回滚。如果运行 DDL 的时候,正在一个事务的中间过程中,会先自动提交当前事务,再执行 DDL。
事务隔离级别
TiDB 只支持 SNAPSHOT ISOLATION
,可以通过下面的语句将当前 Session 的隔离级别设置为 READ COMMITTED
,这只是语法上的兼容,事务依旧是以 SNAPSHOT ISOLATION
来执行。
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
惰性检查
TiDB 中,对于普通的 INSERT
语句写入的值,会进行惰性检查。惰性检查的含义是,不在 INSERT
语句执行时进行唯一约束的检查,而在事务提交时进行唯一约束的检查。
举例:
CREATE TABLE T (I INT KEY);
INSERT INTO T VALUES (1);
BEGIN;
INSERT INTO T VALUES (1); -- MySQL 返回错误;TiDB 返回成功
INSERT INTO T VALUES (2);
COMMIT; -- MySQL 提交成功;TiDB 返回错误,事务回滚
SELECT * FROM T; -- MySQL 返回 1 2;TiDB 返回 1
惰性检查的意义在于,如果对事务中每个 INSERT
语句都立刻进行唯一性约束检查,将造成很高的网络开销。而在提交时进行一次批量检查,将会大幅提升性能。
本优化仅对普通的 INSERT
语句生效,对 INSERT IGNORE
和 INSERT ON DUPLICATE KEY UPDATE
不会生效。
语句回滚
TiDB 支持语句执行的原子性回滚。在事务内部执行一个语句,遇到错误时,该语句整体不会生效。
begin;
insert into test values (1);
insert into tset values (2); -- tset 拼写错误,使该语句执行出错。
insert into test values (3);
commit;
上面的例子里面,第二条语句执行失败,但第一和第三条语句仍然能正常提交。
begin;
insert into test values (1);
insert into tset values (2); -- tset 拼写错误,使该语句执行出错。
insert into test values (3);
rollback;
以上例子中,第二条语句执行失败。由于调用了 ROLLBACK
,因此事务不会将任何数据写入数据库。
事务大小
对于 TiDB 事务而言,事务太大或太小,都会影响事务的执行效率。
小事务
以如下 query 为例,当 autocommit = 1
时,下面三条语句各为一个事务:
UPDATE my_table SET a ='new_value' WHERE id = 1;
UPDATE my_table SET a ='newer_value' WHERE id = 2;
UPDATE my_table SET a ='newest_value' WHERE id = 3;
此时每一条语句都需要经过两阶段提交,频繁的网络交互致使延迟率高。为提升事务执行效率,可以选择使用显式事务,即在一个事务内执行三条语句。
优化后版本:
START TRANSACTION;
UPDATE my_table SET a ='new_value' WHERE id = 1;
UPDATE my_table SET a ='newer_value' WHERE id = 2;
UPDATE my_table SET a ='newest_value' WHERE id = 3;
COMMIT;
同理,执行 INSERT
语句时,建议使用显式事务。
由于 TiDB 中的资源是分布式的,TiDB 中单线程 workload 可能不会很好地利用分布式资源,因此性能相比于单实例部署的 MySQL 较低。这与 TiDB 中的事务延迟较高的情況类似。
大事务
由于 TiDB 两阶段提交的要求,修改数据的单个事务过大时会存在以下问题:
- 客户端在提交之前,数据都写在内存中,而数据量过多时易导致 OOM (Out of Memory) 错误。
- 在第一阶段写入数据耗时增加,与其他事务出现写冲突的概率会指数级增长。
- 最终导致事务完成提交的耗时增加。
因此,TiDB 对事务做了一些限制:
- 单个事务包含的 SQL 语句不超过 5000 条(默认)
- 每个键值对不超过 6 MB
- 键值对的总数不超过 300000
- 键值对的总大小不超过 100 MB
为了使性能达到最优,建议每 100~500 行写入一个事务。