TiDB实例将表中的每一行数据映射成RocksDB中的键值对,则需要考虑如何构造Key和Value。首先,OLTP场景下有大量针对单行或者多行的增、删、改、查等操作,要求数据库具备快速读取一行数据的能力。因此,对应的Key最好有一个唯一ID(显示或隐式的ID),以方便快速定位。其次,很多OLAP型查询需要进行全表扫描。如果能够将一个表中所有行的Key编码到一个区间内,就可以通过范围查询高效完成全表扫描的任务。
基于上述考虑,TiDB中的表数据与Key-Value的映射关系作了如下设计:
- 为了保证同一个表的数据放在一起,方便查找,TiDB会为每个表分配一个表ID,用TableID表示。表ID是一个整数,在整个集群内唯一。
- TiDB会为表中每行数据分配一个行ID,用RowID表示。行ID也是一个整数,在表内唯一。对于行ID,TiDB做了一个小优化,如果某个表有整数型的主键,TiDB会使用主键的值当做这一行数据的行ID。
视频讲解如下 |
---|
【赵渝强老师】TiDB表数据与键值对的映射关系 |
每行数据按照如下规则编码成(Key,Value)键值对:
Key:tablePrefix{TableID}_recordPrefixSep{RowID}
Value:[col1,col2,col3,col4]# 提示:通过查询information_schema.tables可以获取到TableID,例如:
tidb> select tidb_table_id from tables where table_name='DEPT';
+---------------+
| TIDB_TABLE_ID |
+---------------+
| 121 |
+---------------+
对于存在主键或者唯一约束的表,TiDB将会使用主键或者唯一约束条件作为RowID;而对于不存在主键或者唯一约束的表,TiDB将会表自动生成_tidb_rowid。下面是一个简单的示例。
(1)当表有主键的时候是没有这个_tidb_rowid列
tidb> create table table1(id int primary key,name char(30));
tidb> insert into table1 values(1,'AAA');
tidb> select _tidb_rowid from table1;
ERROR 1054 (42S22): Unknown column '_tidb_rowid' in 'field list'
(2)当表不存在主键时,TiDB会自动创建_tidb_rowid且该列初始值是1,递增也是1。
tidb> create table table2(id int,name char(30));
tidb> insert into table2 values(1,'AAA'),(2,'BBB'),(3,'CCC');
tidb> select _tidb_rowid,id,name from table2;
+-------------+------+------+
| _tidb_rowid | id | name |
+-------------+------+------+
| 1 | 1 | AAA |
| 2 | 2 | BBB |
| 3 | 3 | CCC |
+-------------+------+------+
3 rows in set (0.020 sec)
下面通过一个简单的例子,来理解TiDB的Key-Value映射关系。假设TiDB中有如下这个表:
tidb> create table user (id int,name varchar(20),role varchar(20),age int,primary key (id),key idxage (age)
);# 假设该表中有3行数据:
1, "TiDB", "SQL Layer", 10
2, "TiKV", "KV Engine", 20
3, "PD", "Manager", 30
首先每行数据都会映射为一个(Key,Value)键值对,同时该表有一个int类型的主键,所以RowID的值即为该主键的值。假设该表的TableID为10,则其存储在TiKV上的表数据为:
t10_r1 --> ["TiDB", "SQL Layer", 10]
t10_r2 --> ["TiKV", "KV Engine", 20]
t10_r3 --> ["PD", "Manager", 30]
除了主键外,该表还有一个非唯一的普通二级索引idxAge,假设这个索引的IndexID为1,则其存储在TiKV上的索引数据为:
t10_i1_10_1 --> null
t10_i1_20_2 --> null
t10_i1_30_3 --> null