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