一、关系表到KV存储的映射

1、原理

TiDB的存储引擎是一个全局有序的分布式Key-Value引擎TiDB对于每一个表分配一

个TableID,每一个索引都会分配一个IndexID,每一行分配一个RowID,TableID在整个集

群中唯一,IndexID/RowID在表内唯一,这些ID都是int64类型

2、具体实现

(1)每行数据按照如下规则进行编码
Key:tablePrefix{tableID}_recordPrefixSep{rowID}
Value:[col1,col2,col3,col4]
#tablePrefix和recordPrefixSep都是特定的字符串常量
#用于在KV空间中 区分其他的
(2)Unique Index数据的编码
  Key:tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
(3)对于非Unique Index的编码

可能有多行数据的ColumnsValue一样,所以应该这样去编码:

Key:tablePrefix{tableID}_indexPrefixSep{IndexID}_indexedColumnsValue_rowID
Value:null
#Key里面的Prefix都是字符串常量,作用都是区分命名空间,
#以避免不同类型数据之间的相互冲突

每一个Table内部的所有Row都有相同的前缀,一个Index的数据也是有相同的数据的

所以可以非常方便的将Row或者Index数据有序的保存在TiKV中,即一个表中的所有Row

数据就会按照RowID的顺序排列在TiKV的Key空间中,某一个Index的数据也会按照Index

的顺序排列在Key空间内

3、元信息的管理

Database/Table都有元信息,就是表的定义和各项属性,这些信息需要持久化的存

储在TiKV中,每个Database/Table都被分配了一个唯一的ID。这个ID作为唯一的标识,

并且在编码为Key-Value,这个ID都会编码到Key中。这样可以构造出一个Key信息,

Value存储的是序列化后的元信息。除此之外,还有一个专门的Key-Value来存储当前

的Schema信息

二、TiDB的整体结构

JDafud.png

1、TiKV Cluster

主要的作用就是作为KV引擎存储数据

2、TiDB Servers

这一层就是无状态的节点,本身并不会去存储数据,节点之间完全对等;TiDB

Server这一层主要是处理用户的请求,执行SQL逻辑运算

三、SQL层运算

TiDB将SQL查询映射为KV的查询,再通过KV的接口获取对应的数据

1、查询方案的简介

以select count(*) from user where name = "TiDB"为例

  • 构造Key Range:一个表中所有的RowID都在[0,MaxInt64]这个范围内,那么我们可以根

据Row Key编码规则,构造出一个[StartKey,EndKey]这样的左开右闭的区间

  • 根据上面构造出的Key Range。读取TiKV中的数据

  • 过滤数据,对于读取到的每一行的数据,计算name = "TiDB"这个表达式。,如果为真,

向上返回这一行,否则丢弃这一行

  • 根据返回的行数计算Count值

总结该方案的缺点:

  • 从TiKV中读取每一行数据时都要进行一次扫描,但是每次扫描都是一次RPC调用,当扫

描的数据很多时,这个开销非常大

  • 不满足条件的行可以不用读取

  • 只需统计行数即可

2、方案的改进:分布式SQL的运算

将计算、Filter、聚合函数、GroupBy尽量地靠近存储节点,以避免大量的RPC调用

​ 数据逐层返回的示意图如下:

JDwCdI.png

3、SQL层的架构

TiDB的SQL层是非常复杂的,这里我们简单介绍其工作原理:

用户的请求会直接或者通过Load Balancer发送到TiDB-Server,TiDB-Server会解析

MySQL Protocol Packet,获取请求的内容,然后左语法解析、查询特定和优化,执行

查询计划和处理数据。数据全部存储在TiKV的集群中,TiDB和TiKV-Server交互,获取

数据。最后TiDB-Server需要将特定的查询结果返回给特定的用户