- 关于 TiDB
- 快速上手
- 部署标准集群
- 数据迁移
- 运维操作
- 监控与告警
- 故障诊断
- 性能调优
- 系统调优
- 软件调优
- SQL 性能调优
- SQL 性能调优概览
- 理解 TiDB 执行计划
- SQL 优化流程
- 控制执行计划
- 教程
- TiDB 工具
- 功能概览
- 适用场景
- 工具下载
- TiUP
- TiDB Operator
- Dumpling
- TiDB Lightning
- TiDB Data Migration
- Backup & Restore (BR)
- TiDB Binlog
- TiCDC
- sync-diff-inspector
- TiSpark
- 参考指南
- 架构
- 监控指标
- 安全加固
- 权限
- SQL
- SQL 语言结构和语法
- SQL 语句
ADD COLUMN
ADD INDEX
ADMIN
ADMIN CANCEL DDL
ADMIN CHECKSUM TABLE
ADMIN CHECK [TABLE|INDEX]
ADMIN SHOW DDL [JOBS|QUERIES]
ADMIN SHOW TELEMETRY
ALTER DATABASE
ALTER INDEX
ALTER INSTANCE
ALTER PLACEMENT POLICY
ALTER TABLE
ALTER USER
ANALYZE TABLE
BACKUP
BEGIN
CHANGE COLUMN
CHANGE DRAINER
CHANGE PUMP
COMMIT
CREATE [GLOBAL|SESSION] BINDING
CREATE DATABASE
CREATE INDEX
CREATE PLACEMENT POLICY
CREATE ROLE
CREATE SEQUENCE
CREATE TABLE LIKE
CREATE TABLE
CREATE USER
CREATE VIEW
DEALLOCATE
DELETE
DESC
DESCRIBE
DO
DROP [GLOBAL|SESSION] BINDING
DROP COLUMN
DROP DATABASE
DROP INDEX
DROP PLACEMENT POLICY
DROP ROLE
DROP SEQUENCE
DROP STATS
DROP TABLE
DROP USER
DROP VIEW
EXECUTE
EXPLAIN ANALYZE
EXPLAIN
FLASHBACK TABLE
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
RESTORE
REVOKE <privileges>
REVOKE <role>
ROLLBACK
SELECT
SET DEFAULT ROLE
SET [NAMES|CHARACTER SET]
SET PASSWORD
SET ROLE
SET TRANSACTION
SET [GLOBAL|SESSION] <variable>
SHOW [BACKUPS|RESTORES]
SHOW ANALYZE STATUS
SHOW [GLOBAL|SESSION] BINDINGS
SHOW BUILTINS
SHOW CHARACTER SET
SHOW COLLATION
SHOW [FULL] COLUMNS FROM
SHOW CONFIG
SHOW CREATE PLACEMENT POLICY
SHOW CREATE SEQUENCE
SHOW CREATE TABLE
SHOW CREATE USER
SHOW DATABASES
SHOW DRAINER STATUS
SHOW ENGINES
SHOW ERRORS
SHOW [FULL] FIELDS FROM
SHOW GRANTS
SHOW INDEX [FROM|IN]
SHOW INDEXES [FROM|IN]
SHOW KEYS [FROM|IN]
SHOW MASTER STATUS
SHOW PLACEMENT
SHOW PLACEMENT FOR
SHOW PLACEMENT LABELS
SHOW PLUGINS
SHOW PRIVILEGES
SHOW [FULL] PROCESSSLIST
SHOW PROFILES
SHOW PUMP STATUS
SHOW SCHEMAS
SHOW STATS_HEALTHY
SHOW STATS_HISTOGRAMS
SHOW STATS_META
SHOW STATUS
SHOW TABLE NEXT_ROW_ID
SHOW TABLE REGIONS
SHOW TABLE STATUS
SHOW [FULL] TABLES
SHOW [GLOBAL|SESSION] VARIABLES
SHOW WARNINGS
SHUTDOWN
SPLIT REGION
START TRANSACTION
TABLE
TRACE
TRUNCATE
UPDATE
USE
WITH
- 数据类型
- 函数与操作符
- 聚簇索引
- 约束
- 生成列
- SQL 模式
- 表属性
- 事务
- 垃圾回收 (GC)
- 视图
- 分区表
- 临时表
- 字符集和排序规则
- Placement Rules in SQL
- 系统表
mysql
- INFORMATION_SCHEMA
- Overview
ANALYZE_STATUS
CLIENT_ERRORS_SUMMARY_BY_HOST
CLIENT_ERRORS_SUMMARY_BY_USER
CLIENT_ERRORS_SUMMARY_GLOBAL
CHARACTER_SETS
CLUSTER_CONFIG
CLUSTER_HARDWARE
CLUSTER_INFO
CLUSTER_LOAD
CLUSTER_LOG
CLUSTER_SYSTEMINFO
COLLATIONS
COLLATION_CHARACTER_SET_APPLICABILITY
COLUMNS
DATA_LOCK_WAITS
DDL_JOBS
DEADLOCKS
ENGINES
INSPECTION_RESULT
INSPECTION_RULES
INSPECTION_SUMMARY
KEY_COLUMN_USAGE
METRICS_SUMMARY
METRICS_TABLES
PARTITIONS
PLACEMENT_RULES
PROCESSLIST
REFERENTIAL_CONSTRAINTS
SCHEMATA
SEQUENCES
SESSION_VARIABLES
SLOW_QUERY
STATISTICS
TABLES
TABLE_CONSTRAINTS
TABLE_STORAGE_STATS
TIDB_HOT_REGIONS
TIDB_INDEXES
TIDB_SERVERS_INFO
TIDB_TRX
TIFLASH_REPLICA
TIKV_REGION_PEERS
TIKV_REGION_STATUS
TIKV_STORE_STATUS
USER_PRIVILEGES
VIEWS
METRICS_SCHEMA
- UI
- CLI
- 命令行参数
- 配置文件参数
- 系统变量
- 存储引擎
- 遥测
- 错误码
- 通过拓扑 label 进行副本调度
- 常见问题解答 (FAQ)
- 版本发布历史
- 术语表
DEADLOCKS
DEADLOCKS
表提供当前 TiDB 节点上最近发生的若干次死锁错误的信息。
USE information_schema;
DESC deadlocks;
+-------------------------+---------------------+------+------+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+---------------------+------+------+---------+-------+
| DEADLOCK_ID | bigint(21) | NO | | NULL | |
| OCCUR_TIME | timestamp(6) | YES | | NULL | |
| RETRYABLE | tinyint(1) | NO | | NULL | |
| TRY_LOCK_TRX_ID | bigint(21) unsigned | NO | | NULL | |
| CURRENT_SQL_DIGEST | varchar(64) | YES | | NULL | |
| CURRENT_SQL_DIGEST_TEXT | text | YES | | NULL | |
| KEY | text | YES | | NULL | |
| KEY_INFO | text | YES | | NULL | |
| TRX_HOLDING_LOCK | bigint(21) unsigned | NO | | NULL | |
+-------------------------+---------------------+------+------+---------+-------+
DEADLOCKS
表中需要用多行来表示同一个死锁事件,每行显示参与死锁的其中一个事务的信息。当该 TiDB 节点记录了多次死锁错误时,需要按照 DEADLOCK_ID
列来区分,相同的 DEADLOCK_ID
表示同一个死锁事件。需要注意,DEADLOCK_ID
并不保证全局唯一,也不会持久化,因而其只能在同一个结果集里表示同一个死锁事件。
DEADLOCKS
表中各列的字段含义如下:
DEADLOCK_ID
:死锁事件的 ID。当表内存在多次死锁错误的信息时,需要使用该列来区分属于不同死锁错误的行。OCCUR_TIME
:发生该次死锁错误的时间。RETRYABLE
:该次死锁错误是否可重试。关于可重试的死锁错误的说明,参见可重试的死锁错误小节。TRY_LOCK_TRX_ID
:试图上锁的事务 ID,即事务的start_ts
。CURRENT_SQL_DIGEST
:试图上锁的事务中当前正在执行的 SQL 语句的 Digest。CURRENT_SQL_DIGEST_TEXT
:试图上锁的事务中当前正在执行的 SQL 语句的归一化形式。KEY
:该事务试图上锁、但是被阻塞的 key,以十六进制编码的形式显示。KEY_INFO
:对KEY
进行解读得出的一些详细信息,详见 KEY_INFO。。TRX_HOLDING_LOCK
:该 key 上当前持锁并导致阻塞的事务 ID,即事务的start_ts
。
要调整 DEADLOCKS
表中可以容纳的死锁事件数量,可通过 TiDB 配置文件中的 pessimistic-txn.deadlock-history-capacity
配置项进行调整,默认容纳最近 10 次死锁错误的信息。
- 仅拥有 PROCESS 权限的用户可以查询该表。
CURRENT_SQL_DIGEST
列中的信息(SQL Digest)为 SQL 语句进行归一化后计算得到的哈希值。CURRENT_SQL_DIGEST_TEXT
列中的信息为内部从 Statements Summary 系列表中查询得到,因而存在内部查询不到对应语句的可能性。关于 SQL Digest 和 Statements Summary 相关表的详细说明,请参阅Statement Summary Tables。
KEY_INFO
KEY_INFO
列中展示了对 KEY
列中所给出的 key 的详细信息,以 JSON 格式给出。其包含的信息如下:
"db_id"
:该 key 所属的数据库(schema)的 ID。"db_name"
:该 key 所属的数据库(schema)的名称。"table_id"
:该 key 所属的表的 ID。"table_name"
:该 key 所属的表的名称。"partition_id"
:该 key 所在的分区(partition)的 ID。"partition_name"
:该 key 所在的分区(partition)的名称。"handle_type"
:该 row key (即储存一行数据的 key)的 handle 类型,其可能的值有:"int"
:handle 为 int 类型,即 handle 为 row ID"common"
:非 int64 类型的 handle,在启用 clustered index 时非 int 类型的主键会显示为此类型"unknown"
:当前暂不支持的 handle 类型
"handle_value"
:handle 的值。"index_id"
:该 index key (即储存索引的 key)所属的 index ID。"index_name"
:该 index key 所属的 index 名称。"index_values"
:该 index key 中的 index value。
其中,不适用或当前无法查询到的信息会被省略。比如,row key 的信息中不会包含 index_id
、index_name
和 index_values
;index key 不会包含 handle_type
和 handle_value
;非分区表不会显示 partition_id
和 partition_name
;已经被删除掉的表中的 key 的信息无法获取 table_name
、db_id
、db_name
、index_name
等 schema 信息,且无法区分是否为分区表。
如果一个 key 来自一张启用了分区的表,而在查询时,由于某些原因(例如,其所属的表已经被删除)导致无法查询其所属的 schema 信息,则其所属的分区的 ID 可能会出现在 table_id
字段中。这是因为,TiDB 对不同分区的 key 的编码方式与对几张独立的表的 key 的编码方式一致,因而在缺失 schema 信息时无法确认该 key 属于一张未分区的表还是某张表的一个分区。
可重试的死锁错误
DEADLOCKS
表中默认不收集可重试的死锁错误的信息。如果需要收集,可通过 TiDB 配置文件中的 pessimistic-txn.deadlock-history-collect-retryable
配置项进行调整。
当事务 A 被另一个事务 B 已经持有的锁阻塞,而事务 B 直接或间接地被当前事务 A 持有的锁阻塞,将会引发一个死锁错误。这里:
- 情况一:事务 B 可能(直接或间接地)被事务 A 开始后到被阻塞前这段时间内已经执行完成的语句产生的锁阻塞
- 情况二:事务 B 也可能被事务 A 目前正在执行的语句阻塞
对于情况一,TiDB 将会向事务 A 的客户端报告死锁错误,并终止该事务;而对于情况二,事务 A 当前正在执行的语句将在 TiDB 内部被自动重试。例如,假设事务 A 执行了如下语句:
update t set v = v + 1 where id = 1 or id = 2;
事务 B 则先后执行如下两条语句:
update t set v = 4 where id = 2;
update t set v = 2 where id = 1;
那么如果事务 A 先后对 id = 1
和 id = 2
的两行分别上锁,且两个事务以如下时序运行:
- 事务 A 对
id = 1
的行上锁 - 事务 B 执行第一条语句并对
id = 2
的行上锁 - 事务 B 执行第二条语句试图对
id = 1
的行上锁,被事务 A 阻塞 - 事务 A 试图对
id = 2
的行上锁,被 B 阻塞,形成死锁
对于情况二,由于事务 A 阻塞其它事务的语句也是当前正在执行的语句,因而可以解除当前语句所上的悲观锁(使得事务 B 可以继续运行),并重试当前语句。TiDB 内部使用 key 的哈希值来判断是否属于这种情况。
当可重试的死锁发生时,内部自动重试并不会引起事务报错,因而对客户端透明,但是这种情况的频繁发生可能影响性能。当这种情况发生时,在 TiDB 的日志中可以观察到 single statement deadlock, retry statement
字样的日志。
示例 1
假设有如下表定义和初始数据:
create table t (id int primary key, v int);
insert into t values (1, 10), (2, 20);
使两个事务按如下顺序执行:
事务 1 | 事务 2 | 说明 |
---|---|---|
update t set v = 11 where id = 1; | ||
update t set v = 21 where id = 2; | ||
update t set v = 12 where id = 2; | 事务 1 阻塞 | |
update t set v = 22 where id = 1; | 事务 2 报出死锁错误 |
接下来,事务 2 将报出死锁错误。此时,查询 DEADLOCKS
表,将得到如下结果:
select * from information_schema.deadlocks;
+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+
| DEADLOCK_ID | OCCUR_TIME | RETRYABLE | TRY_LOCK_TRX_ID | CURRENT_SQL_DIGEST | CURRENT_SQL_DIGEST_TEXT | KEY | KEY_INFO | TRX_HOLDING_LOCK |
+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+
| 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406216 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000002 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"2"} | 426812829645406217 |
| 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406217 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000001 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"1"} | 426812829645406216 |
+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+
该表中产生了两行数据,两行的 DEADLOCK_ID
字段皆为 1,表示这两行数据包含同一次死锁错误的信息。第一行显示 ID 为 426812829645406216
的事务,在 "7480000000000000355F728000000000000002"
这个 key 上,被 ID 为 "426812829645406217"
的事务阻塞了;第二行则显示 ID 为 "426812829645406217"
的事务在 "7480000000000000355F728000000000000001"
这个 key 上被 ID 为 426812829645406216
的事务阻塞了,构成了相互阻塞的状态,形成了死锁。
示例 2
假设查询 DEADLOCKS
表得到了如下结果集:
+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+
| DEADLOCK_ID | OCCUR_TIME | RETRYABLE | TRY_LOCK_TRX_ID | CURRENT_SQL_DIGEST | CURRENT_SQL_DIGEST_TEXT | KEY | KEY_INFO | TRX_HOLDING_LOCK |
+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+
| 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406216 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000002 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"2"} | 426812829645406217 |
| 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406217 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000001 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"1"} | 426812829645406216 |
| 2 | 2021-08-05 11:09:21.252154 | 0 | 426812832017809412 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000002 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"2"} | 426812832017809413 |
| 2 | 2021-08-05 11:09:21.252154 | 0 | 426812832017809413 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000003 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"3"} | 426812832017809414 |
| 2 | 2021-08-05 11:09:21.252154 | 0 | 426812832017809414 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000001 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"1"} | 426812832017809412 |
+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+
以上查询结果中的 DEADLOCK_ID
列表明,前两行共同表示一次死锁错误的信息,两条事务相互等待构成了死锁;而后三行共同表示另一次死锁信息,三个事务循环等待构成了死锁。
CLUSTER_DEADLOCKS
CLUSTER_DEADLOCKS
表返回整个集群上每个 TiDB 节点中最近发生的数次死锁错误的信息,即将每个节点上的 DEADLOCKS
表内的信息合并在一起。CLUSTER_DEADLOCKS
还包含额外的 INSTANCE
列展示所属节点的 IP 地址和端口,用以区分不同的 TiDB 节点。
需要注意的是,由于 DEADLOCK_ID
并不保证全局唯一,所以在 CLUSTER_DEADLOCKS
表的查询结果中,需要 INSTANCE
和 DEADLOCK_ID
两个字段共同区分结果集中的不同死锁错误的信息。
USE information_schema;
DESC cluster_deadlocks;
+-------------------------+---------------------+------+------+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+---------------------+------+------+---------+-------+
| INSTANCE | varchar(64) | YES | | NULL | |
| DEADLOCK_ID | bigint(21) | NO | | NULL | |
| OCCUR_TIME | timestamp(6) | YES | | NULL | |
| RETRYABLE | tinyint(1) | NO | | NULL | |
| TRY_LOCK_TRX_ID | bigint(21) unsigned | NO | | NULL | |
| CURRENT_SQL_DIGEST | varchar(64) | YES | | NULL | |
| CURRENT_SQL_DIGEST_TEXT | text | YES | | NULL | |
| KEY | text | YES | | NULL | |
| KEY_INFO | text | YES | | NULL | |
| TRX_HOLDING_LOCK | bigint(21) unsigned | NO | | NULL | |
+-------------------------+---------------------+------+------+---------+-------+