区块链上的“SQL”

article/2025/9/4 19:22:29

导读

《F1:A Distributed SQL Database That Scales》是Google构建的用于支持广告业务的分布式关系型数据库系统。作为一个混合型数据库系统,它结合了高可用、NoSQL数据库的扩展性以及传统SQL数据库的一致性可用性。F1数据库整体基于Google Spanner构建,Spanner主要为上层的F1提供了跨数据中心的数据复制功能和一致性保证。而F1通过使用结构化数据分层架构模型和合理的应用设计,来降低数据备份带来的延迟,并提供了全功能的SQL支持。该论文也成为很多厂商实现合约中的SQL功能的重要参考。

区块链执行SQL的可能性

业务系统中的数据是以结构化的组织存在,使用结构化语言查询可以极大提升业务人员访问数据的便捷性。

SQL(Structured Query Language,结构化查询语言)是一种特定目的的编程语言,广泛应用于关系数据库管理系统,例如大家所熟知的MySQL、Oracle等。SQL是高级的非过程化编程语言,它允许用户在高层数据结构上工作,不需要用户指定对数据的存放方法,也不需要用户了解其具体的数据存放方式,这种灵活的方式自然衍生出了很多优秀的SQL执行引擎。

以我们熟知的MySQL为例,其中就包括了InnoDB、MyIsam和Memory等执行引擎,不同的执行引擎之间各有优劣,在不同的使用场景上会发挥出不同的作用,但是其向上的表现却是一致的,由此我们衍生出了在传统区块链的基础上来构建高效可用的SQL执行引擎的设计思想。

存储引擎从很大程度上限制了执行引擎的实现,传统的区块链系统一般会采用键值对的NoSQL数据库,将产生的状态数据以键值对的形式进行存储,同时方便世界状态的计算。为了保证区块链底层的存储结构不发生大的变化,我们需要设计一个方式,尽可能将SQL执行引擎建立在键值对数据库之上。在Google的F1中本身就是基于NoSQL数据库进行扩展,这让在区块链上执行SQL有了一定的可能性。

然而问题在于,要想解决区块链上执行SQL语句,就必须要解决SQL语句的编译问题以及如何将SQL的结构化数据保存到KV数据库当中,这也是我们本篇分享的主要内容:SQL编译与数据存储

SQL编译

同大部分语言一样,SQL编译主要是将SQL语言转化为AST(Abstract Syntax Tree,抽象语法树),然后才能基于生成的语法树来设计我们的执行引擎。

既然谈到了编译,必然离不开在编译原理中离不开的两个话题:词法分析语法分析

词法分析是将字符序列转换为标记(token)的过程;语法分析则是根据某种给定的形式文法对token构成的输入文本进行分析并确定其语法结构的一种过程,主要作用是进行语法检查并构建有输入的token组成的数据结构(一般是语法分析树、抽象语法树等层次化的数据结构)。

如果通俗的来讲,将编程语言的编译类比为自然语言,那么词法分析关注的是你说了什么内容,语法分析则是关注与你说的内容是不是正确的,是否能够让人理解的。

词法分析相对而言比较简单,语法分析则相对来说会复杂很多,笼统地说语法分析方法可以分为自顶向下分析算法和自底向上分析算法,两者的主要区别是一种是“扩展”,一种是“规约”,至于语法分析是如何工作的,此处篇幅有限不再过多展开介绍,读者可自行了解编译的语法分析方法,包括遇到歧义或要回溯时是如何处理的。

图片

上述算法依据的语法规则一般称之为上下文无关语法,一个语法表达式一般会表达为S->AB的形式,将产生式左侧的符号称之为非终结符,代表可以继续扩展或产生的符号;只能出现在右边的称之为终结符,无法再产生新的符号。

BNF(Backus Normal Form,巴科斯范式)是一种用于表示上下文无关语法的语言,事实上很多编译器都是可以通过编写类似的语法表达式,用工具直接生成一个编译器,如Java编译器就是通过Antlr4来生成的。

尽管有现成的方式可以帮助我们生成编译器,但是完整的描述出SQL语言的语法表达式本身就是一件繁琐且工作量很大的事,索性我们能从很多地方获取到这个语法表达式文件,例如从MySQL官网可以获取到MySQL的语法表达式(因为“SQL方言”的存在不同SQL数据库语法表达式会略微不同),在现有的SQL语法表达式的基础上进行修改可以大大减少设计工作量。

CREATE TABLE IF NOT EXISTS testTable
(
id bigint(20) NOT NULL, 
name varchar(32) NOT NULL, 
exp bigint(20) NOT NULL DEFAULT '0'
);

这是一个创建数据表的SQL语句,我们可以用这样的范式来表示我们的创建表的过程:

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name(create_definition,...)[table_options][partition_options]

如果范式中包含其他的子范式,当其被匹配到时,就会执行我们所期望的流程。

例如使用goYacc我们可以将我们定义的范式逻辑转化为一个golang语言的编译器,假设基于goYacc将其中一种创建表的SQL范式编写为如下:

CreateTableStmt:"CREATE" OptTemporary "TABLE" IfNotExists TableName TableElementListOpt AsOpt{stmt := $6.(*ast.CreateTableStmt)stmt.Table = $5.(*ast.TableName)stmt.IfNotExists = $4.(bool)stmt.IsTemporary = $2.(bool)$$ = stmt}

其中$$表示的范式的最终返回值,$x表示的第x个位置的返回值,如$4表示的就是IfNotExists返回的结果,而AST的节点数据结构则需要我们事先定义好。

最终我们可以将上述创建表的SQL语句生成为一个AST的结构如下所示(忽略了name字段的展示):

图片

当有了AST这个数据结构之后,就可以使用Visitor模式对树的每个节点进行访问,来获取我们想要的信息以及生成执行过程。

数据存储

通过上一小节,相信大家对SQL的编译以及AST有了一个基本的概念,现在来讨论另一个问题,如何将SQL数据存入到键值对数据引擎中。

主要分为:表信息存储、表内行数据存储以及索引存储。

▲ 表信息存储

对于数据表的信息,例如表名、行信息和索引信息等这些内容,可以将表结构以某种序列化方式转化为二进制格式来进行保存,键值对的key则可以为每个表生成一个唯一的表ID,来作为表信息的索引,当需要使用对应的表结构时,只需将其反序列化为表结构即可,相对来说表信息转化为键值对保存是比较容易的。

▲ 表内行数据存储

数据表内的行数据存储会复杂一些,以上述创建的SQL表为例,假设向其中插入的某一条数据的SQL语句如下:

INSERT INTO testTable (id, name) VALUES(001, "tom");

首先,我们要确定这一行数据的key,可以将key的生成规则抽象的表示为:

tablePrefix{TableID}_recordPrefixSep{RowID}。

其中tablePrefix和recordPrefixSep都是固定前缀,用于标识表和行信息的开始,而TableID则为创建表时生成的唯一ID,对于行ID,当表内存在整数型的主键则会将这一主键值作为行ID,否则将同样会为改行分配一个唯一的行ID,由此一行数据的key可以确定下来。

对于一行数据的value,可以将每一列的数据紧凑的排列在一起即可,例如上述描述的插入语句的数据,用16进制来表示可以描述为01746f6d00,01表示的列id的值,746f6d表示的是列name的值(即"tom"),00则表示列exp的默认值,而这些数据的类型可以从表信息中获取到,无需保存在行的value中。

当然这样表示一行数据的value肯定是不够的,实际上还需要基于数据编码的基础上增加:版本号、该行内容包含的列数据数量、分别是哪些列的数据以及每一列的数据起始偏移等,附带上这些额外的信息后才是一个完整的一行数据。

图片

▲ 索引存储

另一个比较关键数据就是对索引的存储,需要再次说明的是:对于一个表内的每一列信息,都会分配一个唯一列ID来进行标识。

索引主要分为唯一索引和非唯一索引两类

唯一索引在存储时将索引值作为key,行ID作为value来进行索引信息的保存,具体的一个唯一索引key表示为:

tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue

indexPrefixSep同样为固定前缀,用于表示索引列信息的开始,所以一个完整的唯一索引信息key还包含了表ID和列ID。

非唯一索引在存储时将索引值和行ID组合未做key,value则保存空值,通过依赖于存储引擎在遍历时按字典序的特点获取到对应的非唯一索引下的所有行ID,具体一个非唯一索引key表示为:

tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue_rowID

同样的一个完整的非唯一索引key还包含了表ID和列ID。

综上,通过对于SQL编译处理以及SQL数据键值对存储,让大家可以大致的了解常见的SQL数据如何存储到键值对存储引擎中的设计理念。

小结

本文主要介绍了SQL的编译处理以及如何将SQL转化到键值对存储引擎的技术方案,引发了如何基于现有的区块链架构来执行SQL语句的思考,如何通过SQL执行来拓宽区块链的业务使用场景的实践。

但这远没有结束,此过程之中还有很多问题需要我们研究思考,例如如何进行外键关联,如何进行复杂的笛卡尔积查询以及如何合理度量SQL执行的复杂度。

同样需要注意的是,并不是所有的需求都适合于区块链,例如基于非索引的查询在目前的区块链系统中就显得很不合理,这需要存储引擎的的配合。

总的来说在区块链上执行SQL并不是不可能的,但需要我们不断的去探索一个合理的可以高效的在区块链上执行SQL功能的解决方案:更易用、更高效、更强大。

大家看了这篇文章如果有好的想法,欢迎在评论区与我们交流。

 

参考文献

[1]《F1: A Distributed SQL Database That Scales》:https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/41344.pdf

[2] HTAP DB:http://www.vldb.org/pvldb/vol13/p3072-huang.pdf

[3] MySQL Statements:https://dev.mysql.com/doc/refman/5.7/en/sql-statements.html

[4] goYacc:https://godoc.org/golang.org/x/tools/cmd/goyacc

[5] TiDB parser:https://github.com/pingcap/parser

[6] TiDB架构介绍:https://pingcap.com/blog-cn/#%E6%9E%B6%E6%9E%84

 

作者简介

陶烨琪

来自趣链科技基础平台部,区块链虚拟机研究小组

 

有任何想了解的技术问题、对文章的建议

欢迎进技术交流群和我们一起探讨~

添加小助手桔子(微信:18458407117


http://chatgpt.dhexx.cn/article/su3UjvxL.shtml

相关文章

学习区块链经典教程:区块链技术与应用

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情 本课程主要讲解区块链的基本概念和实现原理,面向具有计算机相关的基础知识,对区块链技术和应用感兴趣的同学。通过这门课的学习&#xff0c…

深入浅出区块链技术

大厂技术 坚持周更 精选好文 本文为纯粹区块链技术分享,没有任何投资建议。希望大家喜欢~ 一、故事导读 开始分享之前,引用自网上一个段子来引导大家。 《小明的故事》 小明是谁?小明是一名前端工程师,也是一个足球迷…

区块链相关技术学习总结(1)——区块链以及区块链技术入门详解

区块链是目前一个比较热门的新概念,蕴含了技术与金融两层概念。从技术角度来看,这是一个牺牲一致性效率且保证最终一致性的的分布式的数据库,当然这是比较片面的。从经济学的角度来看,这种容错能力很强的点对点网络,恰…

p7结构的数字信封

PKCS7的数字信封格式分为两种:带签名的数字信封和不带签名的数字信封。由于这个数字信封的生成过程比较复杂,所以这两种格式比较容易记混,导致都搞不清楚一个数字信封里面到底是存储的什么内容了。下面我就详细的解释一下,这两种数…

数字签名和数字信封

数字签名和数字信封 数字签名定义原理作用签名种类P7签名又分为两类:Attached签名Detached签名P1签名也称为裸签 验证签名验签的原理 数字信封定义原理作用 签名 、数字信封、证书的关系 数字签名 定义 用户用自己的【私钥】对原始数据的哈希摘要进行加密所得的数…

chewing的作业——数字信封实现文件传输

文件安全传输系统设计作业 通信模式:端到端通信 数字信封: 对称密码优点是加解密运算非常快,适合处理大批量数据,但其密码的分发与管理比较复杂。而非对称密码算法的特点是公钥和私钥分离,非常适合密钥的分发和管理。…

什么又是数字证书?(数字证书与数字签名什么关系?)数字信封、PGP又是啥?

什么是非对称加密? 什么是信息摘要? 什么是数字签名? 本节我们接着上面的内容继续,话说有了非对称加密技术、有了信息摘要技术、也有了数字签名技术,信息的安全传输是不是就万无一失了呢? 其实并不完全&a…

sm2格式数字信封加解密详解

sm2格式数字信封 0、参考链接 密码行业标准化技术委员会http://www.gmbz.org.cn/main/bzlb.html SM2密码算法使用规范http://www.gmbz.org.cn/main/viewfile/2018011001400692565.html SM2密码算法应用分析https://blog.csdn.net/arlaichin/article/details/23708155?utm_so…

数字签名和数字信封的比较

参考博客:数字签名与数字信封流程 相同点 都使用了非对称算法对密钥进行了加密 数字签名 重点:防止文本被篡改,防止抵赖 发送方将文本取摘要,再生成一个密钥对摘要加密,同时该密钥使用自己的私钥进行非对称加密&am…

密码学~~~数字信封

#本文仅供参考有不足之处请指出 一、概括 数字信封是公钥密码体制在实际中的一个应用,是用加密技术来保证只有规定的特定收信人才能阅读通信的内容。数字信封的功能类似于普通信封,普通信封在法律的约束下保证只有收信人才能阅读信的内容;数…

数字信封工作原理

数字信封是指发送方使用接收方的公钥来加密对称密钥后所得的数据,其目的是用来确保对称密钥传输的安全性。采用数字信封时,接收方需要使用自己的私钥才能打开数字信封得到对称密钥。 数字信封的加/解密过程如图1-19所示。甲也要事先获得乙的公钥&#xf…

RSA+AES数字信封加解密设计

登录认证、鉴权这些都做好了过后。就开始我们的加密设计了、这里采用了简化数字信封进行加密。首先客户端(浏览器)先请求一份RSA非对称密钥、如果我们采用了openresty或者有能力在nginx开发C模块的插件,就可以在这里保留一份用户的私钥&#…

数字信封加密

OpenSSL 是目前 PHP 甚至是整个开发圈中的数据加密事实标准,包括 HTTPS/SSL 在内的加密都是它的实际应用, OpenSSL 提供了对称和非对称加密的形式,也就是我们日常中最普遍的两种加密方式。 那么,它和 Hash 类的加密有什么不同吗&…

p7数字信封

PKCS7的数字信封格式分为两种:带签名的数字信封和不带签名的数字信封。由于这个数字信封的生成过程比较复杂,所以这两种格式比较容易记混,导致都搞不清楚一个数字信封里面到底是存储的什么内容了。下面我就详细的解释一下,这两种数…

数字信封原理

数字信封是指发送方使用接收方的公钥来加密对称密钥后所得的数据,其目的是用来确保对称密钥传输的安全性。采用数字信封时,接收方需要使用自己的私钥才能打开数字信封得到对称密钥。 数字信封的加/解密过程如图所示。甲也要事先获得乙的公钥,…

PKCS7数字信封简述

1、数字信封的概念 数字信封,英文是Digital Envelope,望文生义,就可以知道将需要传递的数据,通过加密的方式包裹起来。 数字信封的准确定义,在《PKCS #7: Cryptographic Message Syntax Standard》标准的第10章中给出,原话是:“加密的内容,以及对内容解密的密钥被加密…

什么是数字信封?

一、什么是数字信封 数字信封是公钥密码体制在实际中的一个应用,是用加密技术来保证只有规定的特定收信人才能阅读通信的内容。 在数字信封中,信息发送方采用对称密钥来加密信息内容,然后将此对称密钥用接收方的公开密钥来加密(这…

数据来源渠道及采集工具_几款简单好用的爬虫抓取数据采集工具

新朋友点上方蓝字“Office交流网”快速关注 1. 火车头采集器 火车采集器我们也一直在用,是老牌的采集工具了。它不仅可做抓取工具,也可以做数据清洗、分析、挖掘已经可视化等工作。数据源可来源于网页,网页中能看到的内容和不可看到都可以通过…

爬虫抓取新浪微博数据

工具:云采爬虫 目标:抓取某个博主的全部微博 分析网页结构: 我们抓取的思路是模拟浏览器自动访问页面抓取。 我们来看一下页面结构,首先每个微博列表,必须进行三四次的下拉加载,如果底部有个翻页的按钮…

python3 爬虫抓取股市数据

python3 爬虫抓取股市数据 爬虫抓取数据的一般步骤代码运行结果小结注意事项 爬虫抓取数据的一般步骤 1、确定需要抓取的网站2、分析url,找到url的的变化规律3、分析页面的数据4、获取页面数据5、提取需要爬取的数据6、写入数据库或写入文件代码 import requests i…