乐趣区

关于mysql:InnoDB的ID家族ROWIDXIDTRXIDTHREADID

前言

随着对 mysql 的深刻了解,以及接触 mysql 越来的频繁,发现 mysql 的这些 ID 们在整个 mysql 中的作用非常可观,因而对于这些 ID,专门写一篇文章来让大家介绍和深刻的了解,目前文章中列出来的是比拟罕用的和我所想到的这几个 ID,后续有其余的会持续补充。


一、什么是 ROW_ID?

ROW_ID

If a table has a PRIMARY KEY or UNIQUE NOT NULL index that consists of a single column that has an integer type, you can use _rowid to refer to the indexed column in SELECT statements

简略翻译一下,如果在表中存在 主键 非空惟一索引 ,并且仅由一个 整数类型 的列形成,那么就能够应用 SELECT 语句间接查问_rowid,也就是说 row_id 就是行索引 id。
总结一下就是三个条件:

1.,主键
2.,非空惟一索引
3.,整数类型

接下来看看这些条件在以下各个场景组合会产生什么?
后果就先放进去:

  • 若只存在主键 + 整型 -》row_id 失效,取主键值
  • 若只存在非空惟一索引 + 整型 -》row_id 失效,取非空索引值
  • 若存在多个非空惟一索引 -》row_id 严格取第一个,满足就无效,第一个不满足就生效。

    • 若主键和非空惟一索引同时存在 -》row_id 失效,取主键值。
    • 若主键和非空惟一索引都不存在:取全局变量 dictsys.row_id

    测试场景 1:
    设置了主键,并且主键字段是数值类型的状况下,_rowid 间接援用了主键字段的值,这种叫显示 rowid。


改了主键类型为 varchar,就报错了。

其余的几个场景我就不在这一一举例了,有趣味的能够本人去测试一下。

二、什么是 XID?

XID
Xid 是由 server 层保护的。InnoDB 外部应用 Xid,就是为了可能在 InnoDB 事务和 server 之间做关联。
Xid 在 MySQL 外部的生成逻辑:

  1. MySQL 外部保护一个全局变量 global_query_id**
  2. 每次执行语句的时候将 global_query_id -> Query_id, 而后 global_query_id+1**
  3. if(事务执行的第一条语句){Query_id->XID}**

global_query_id是一个纯内存变量,重启之后清零
• 因而,在同一个数据库实例中,不同事务的 XID 也有可能是雷同的
• MySQL 重启之后,会从新生成新的 binlog
保障:同一个 binlog 文件里,XID 是惟一的
• global_query_id 达到下限后,就会持续从 0 开始计数
因而实践上,同一个 binlog 还是会呈现雷同的 XID,只是概率极低

global_query_id是 8 Bytes,下限为 2^64-1

• 执行一个事务,假如 XID 是 A

• 接下来执行 2^64 次查问语句,让 global_query_id 回到 A

• 再启动一个事务,这个事务的 XID 也是 A(相似 row_id 超出最大值后清零,从新开始)

xid 的存在的意义
redo log 和 binlog 有一个独特的数据字段,叫 XID,解体复原的时候,会按程序扫描 redo log:

  • 如果碰到既有 prepare、又有 commit 的 redo log,就间接提交;
  • 如果碰到只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务。

三、什么是 TRX_ID?

TRX_ID
Xid 和 InnoDB 的 trx_id 是两个容易混同的概念。
Xid 是由 server 层保护的。InnoDB 外部应用 Xid,就是为了可能在 InnoDB 事务和 server 之间做关联。然而,InnoDB 本人的 trx_id,是另外保护的。
InnoDB 外部保护了一个 max_trx_id 全局变量,每次须要申请一个新的 trx_id 时,就取得 max_trx_id 的以后值,而后并将 max_trx_id 加 1。
InnoDB 数据可见性的核心思想是:每一行数据都记录了更新它的 trx_id,当一个事务读到一行数据的时候,判断这个数据是否可见的办法,就是通过事务的一致性视图与这行数据的 trx_id 做比照
对于正在执行的事务,你能够从 information_schema.innodb_trx 表中看到事务的 trx_id。

当初,咱们一起来看一个事务现场:

1. 事务 1 时刻

session A 还没有波及到更新,是一个只读事务。

对于只读事务,InnoDB 并不会调配 trx_id

所以事务 2 时刻去查事务 trx_id 是一个很大的值,这个很大的 trx_id 是由零碎长期计算出来的,是把以后事务的 trx 变量的指针地址转成整数,再加上 2^48。
为什么值这么大?
目标是要保障只读事务显示的 trx_id 值比拟大,失常状况下就会区别于读写事务的 id

只读事务不调配 trx_id 的益处

• 能够缩小事务视图外面沉闷数组的大小

以后正在运行的只读事务,是不影响数据的可见性判断
因而,在创立事务的一致性视图时,只须要拷贝读写事务的 trx_id

• 能够缩小 trx_id 的申请次数

在 InnoDB 里,即便只执行一条一般的 SELECT 语句,在执行过程中,也要对应一个只读事务
如果一般查问语句不申请 trx_id,就能够大大减少并发事务申请 trx_id 的锁抵触
因为只读事务不调配 trx_id,trx_id 的减少速度会变慢。

1. 事务 3 时刻
此时,InnoDB 才真正调配 trx_id。

四、什么是 THREAD_ID?

THREAD_ID
1、SHOW PROCESSLIST的第一列就是 thread_id

2、零碎保留了一个环境变量thread_id_counter

• 每新建一个连贯,就将 thread_id_counter 赋值给这个 新连贯的线程变量


3、thread_id_counter 定义为 4 Bytes,因而达到 2^32- 1 后就会重置为 0
• 但 不会 在 SHOW PROCESSLIST 外面看到 两个雷同 的 thread_id
• 因为 MySQL 设计了一个惟一数组的逻辑,给新线程调配 thread_id,逻辑代码如下

do {new_id= thread_id_counter++;} while (!thread_ids.insert_unique(new_id).second);

以上,就是 mysql 中比拟罕用的这几个 ID,后续有其余的会持续补充,心愿大家多多关注反对。

退出移动版