YashanDB SQL 语言
SQL 简介
结构化查询语言(SQL,Structured Query Language)是一种关系型数据库的操作语言,用于数据存取、数据查询、数据处理和关系型数据库系统管理。SQL 提供一个操作关系型数据库的接口,且内置了安全访问机制检查。所有应用都可以使用 SQL 语句访问 YashanDB 数据库中的数据。
SQL 语言一种非过程化的声明性语言,只需描述语句的目的(做什么样的数据操作),无需提供实现的过程。因此,YashanDB 在处理 SQL 时,需要先使用 SQL 编译器生成基于 SQL 目标的过程结构-执行计划,再操作数据库,最终执行算子得到对应结果集。
SQL 语言的存在可以帮助用户只需聚焦于数据处理本身无需过于关注实现过程,例如统计一个公司所有部门下转正员工的平均工资,SQL 语句示例如下:
该查询语句中,GROUP BY 完成部门分组操作,HAVING 完成转正员工过滤,AVG 完成平均工资求值,ORDER BY 实现按部门排序。执行该语句时,数据库将自动组织 EMPLOYEE 基表的数据,按行进行分组、过滤、排序、聚集、投影操作,最终返回语句预期的结果集。
所有 SQL 语句都是由优化器依据 YanshanDB 特定的代价模型生成最优的执行计划,该计划受统计信息、代价计算公式、HINT、OUTLINE 等功能影响。
所有计划的执行都是由 YashanDB 的执行引擎完成,包括火山执行引擎和向量化执行引擎,执行对象为执行计划定义的各个执行算子。
#SQL 标准
SQL 语言是由美国国家标准化协会和国际标准化组织共同定义的一种标准化语言,行业中最主要的标准为SQL92
和SQL99
。2023 年,发布了ISO/IEC 9075:2023
SQL 标准。从表的定义、数据类型、各类查询功能等不断演化,到最新纳入 JSON 半结构化数据标准。
但业界主流的各大数据库,在 SQL 实现上均有差异,所以业界又常用“方言”来代指在标准外、因数据库具体实现带来差别的 SQL 语言。
#SQL 语句
在 YashanDB 数据库中,SQL 语句是进行数据处理的主要途径。SQL 语句是一种承载数据操作目的的声明性语句,由关键字、标识符、绑定参数、字面量等组成。
关键字
指在 SQL 语句中用于定界语法位置或标识数据类型等特殊用途,不能被随意使用的词语。关键字组成 SQL 语句的语法目的。例如,INTEGER 是关键字,表示整数的数据类型,不能被用作列名。
标识符
指在 SQL 语句中用于标识某种资源,用于命名的词语。标识符表示 SQL 语句的语法处理对象。
例如,如下建表语句中,EMPLOYEE 是表示表名的标识符,DEPARTMENT_ID 和 SALARY 是表示列名的标识符。
绑定参数
指在 SQL 语句中为了减少重复、相似的 SQL 操作,节约编译时间,将出于相似目的 SQL 操作中变化的部分用绑定参数代替。
例如,如下 DML 语句中,符号“?”表示可以绑定不同值的绑定参数。
字面量
指在 SQL 语句中直接通过组成 SQL 语句的字符串来表示具体的数值、字符串和特定类型的常量。当字面量要表示字符串时,需要使用单引号''
包围进行转义。
例如,如下 DML 语句中,字符串'10'
,'20000'
表示进行特定列筛选的数值。
SQL 语句必须是完整而且符合语法分支要求的 SQL 句子,当 SQL 语句不满足 YashanDB 的语法要求时会报错。
YashanDB 提供的 SQL 语句包括:
数据定义语言(DDL):提供数据库对象的创建、修改、删除操作。
数据操作语言(DML):提供数据增加、删除、修改、查询操作。
数据控制语言(DCL):提供数据访问的事务机制、权限控制、访问控制等操作。
#数据定义语言(DDL)
数据定义语言(DDL,Data Define Language)提供对数据库对象的创建、修改、删除操作。数据库对象包括用户、表空间、表、索引、视图、序列、同义词、存储过程、自定义函数、触发器、高级包等数据库结构,还包括数据库本身。
YashanDB 数据库安装完成后,首次启动时默认进入 NOMOUNT 阶段,需要先执行创建数据库的 DDL 语句,才能提供数据库服务。
常见的 DDL 语句包括 CREATE、ALTER 及 DROP 数据库对象、TRUNCATE 清空表数据、SHUTDOWN 数据库等。
很多 DDL 语句支持在线修改数据库对象的属性,例如在不停止对表的访问情况下并发对表增加列属性。
数据库在执行 DDL 语句前,会触发事务提交操作,将 DDL 语句前的事务结束。避免当前 DDL 语句产生的元数据变更事务与之前可能已存在的事务发生混淆。无论当前 DDL 语句执行成功与否,它之前的事务都会被提交结束。
#数据操作语言(DML)
数据操纵语言(DML,Data Manipulation Language)提供了对数据库进行 INSERT 插入、UPDATE 更新、DELETE 删除、MERGE 合并数据以及 SELECT 查询的能力,允许单表、多表数据操作。
INSERT 插入语句可以使用独立的 SQL 语句单句执行,可以使用绑定参数批量执行,也可以使用 INSERT INTO TABLE SELECT 直接从查询结果集获取数据。
DML 会修改数据状态,一个事务中包含 DML 语句时,事务由执行第一条 DML 语句自动启动,通过 AUTO_COMMIT 参数可以控制是否每条 DML 语句自动提交。更新和删除语句会先根据过滤条件从数据库中扫描目标数据再进行修改,若修改过程中发生一致性校验失败,会重启 SQL 语句,重新扫描数据再修改。
根据 SQL 规范,事务内已执行待提交的数据修改对当前事务内的后续 SQL 语句可见。
为了加强一条 SQL 对数据库修改的能力,YashanDB 支持合并操作(MERGE INTO),支持 INSERT、UPDATE、DELETE 的复合语法,通过复用一次查询的结果集更加高效和灵活地修改数据。
SELECT 可以一次查询多个或单个表或视图并经过一系列计算,最终得到一个结果集。不论查询的是 HEAP 表、LSC 表或 TAC 表,查询结果集的组织方式都是相同的。查询执行的过程就是计划树的执行流程。查询计划树由一系列算子构成,为了能够加快查询速度,会将计划树的算子分成多个阶段,每个阶段通过数据交换算子传输数据,多个阶段可以同时执行,每个阶段的实例也可以并行执行。为了进一步提升查询效率,很多场景可以通过向量化计算进行查询加速。
#数据控制语言(DCL)
数据控制语言(DCL,Data Control Language)提供数据访问的事务机制、权限控制、访问控制等操作。
事务控制语句可以对事务进行 COMMIT 提交、ROLLLBACK 回滚、SAVEPOINT 设置回滚保存点以及 ROLLLBACK TO SAVEPOINT 基于 SAVEPOINT 的回滚操作。
授权和授权回收语句包括 GRANT 授予权限和 REVOKE 授权回收,是基于用户或角色进行的权限粒度控制。
访问控制语句提供了动态管理用户建链后的会话属性,会话是数据库实例中表示登录用户的一个连接状态。从该用户输入用户名、密码通过权限认证后,数据库分配会话提供服务,一直到用户断开连接结束会话服务。在整个会话过程中,都可以通过 ALTER SESSION 语句对当前会话进行调整。
DCL 语句中还包括了 ALTER SYSTEM 更改数据库实例级参数属性的能力。
#优化器
优化器是 SQL 引擎的核心组成部分,负责将用户输入语句转换为数据库的执行表示(执行计划),引擎按照优化后的最优执行计划执行。
优化器通过对用户输入语句和数据库存储数据的分析制定高效的执行计划,分析主要包括查询条件分析、可选的访问路径、系统配置参数、数据统计信息、是否使用 Hint 提示等。
优化器主要包含以下优化操作:
条件补充和移动,例如,
A = B and A = 5
,会补充出B = 5
,对 B 相关的数据进行过滤。语句静态重写与动态重写,根据关系代数的等价变化,将语句转换为可以扩展出更多路径的表示方式。
连接顺序的确定,根据 Join 的交换律合结合律,确定 join 的顺序。
访问路径的扩展。
路径评估和选择,计算每条路径的成本,选择出成本最低的路径做为最优路径。
优化器尽可能的扩展每个 SQL 语句可以执行的所有方式,再通过成本计算选出成本最低的一种执行计划做为最终的查询执行计划。在 SQL 实际执行前,用户可以打印优化器的执行计划,评估语句执行效率的高低。
如果计划不符合预期,可以通过一系列方法来影响执行计划:
调整统计信息,使其更接近实际数据分布。
调整数据库相关的参数。
Hint 使用提示。
#优化器组件
优化器主要包括以下几个组件:
静态优化与转换组件
将查询转换为另一种表示的等价形式,等价形式有助于产生一个更好的计划。例如:
outer join
转换为inner join
。动态转换组件
动态转换为语句产生尽可能多的等价形式(但不确定哪种形式更优),可以通过成本计划选出最优形式,例如,
group by
下推。基数估算与成本计算模块组件
负责评估计划种每个算子的选择率,基数和对应的执行成本。
计划选择组件
通过遍历所有可用计划的成本,选出成本最低的计划,做为最终的执行计划。
#优化器统计
统计信息是对数据库中所有对象以及各种对象中数据分布和结构的概括性描述,与执行时的动态视图的统计不同。优化器根据统计信息了解具体对象的数据情况,从而选择合适的执行算法。
常用的统计信息包括:
表统计信息,行数,块数,行平均长度等。
列统计信息,非重复值的个数,空值个数,最大最小值,以及直方图表示的数据分布等。
索引统计,索引的层数,叶子节点块数,索引与数据之间的聚簇关系等。
统计信息收集完后存储在对应的字段表中,当数据发生较大变化时,统计信息需要对应的更新以更准确的反应真实数据。
#优化器提示
某些场景中,数据库管理员或应用程序开发人员比优化器更了解特定应用的数据的分布情况,更清楚在这种分布下该选择哪个计划更优。此时,可以在 SQL 语句中添加 HINT 提示建议优化器以何种方式执行。
提示是一种建议性的行为,不能完全保证优化器按照提示所指定的方式执行,输入无效提示时,优化器会直接忽略提示的存在。
优化器支持的主要提示方式包括:
数据扫描方式,例如表扫描,索引扫描等。
关联方式与关联顺序,例如散列连接,循环嵌套连接等。
并行、批量相关的提示。
#SQL 处理
YashanDB 会将 SQL 语句文本转换为数据库对象和操作序列,实现对数据库的访问和修改。
#SQL 处理阶段
软解析(SOFT PARSE)阶段,计划缓存校验,YashanDB 将 SQL 语句文本与计划缓存中的副本进行比对,若两者匹配成功并且计划缓存不包含失效的数据库对象,则直接使用缓存中的计划。
解析(PARSE)阶段,若计划缓存查找失败,解析器根据 SQL 语法树,从前往后读取 SQL 文本,进行语法校验,生成抽象语法树。
语义校验(VERIFY)阶段,将抽象语法树翻译成数据库对象,并进行语义校验,例如表是否包含查询的字段。
静态重写(REWRITE)阶段,使用静态改写规则对抽象语法树进行等价变换。
优化(OPTIMIZE)阶段,通常是对查询部分进行优化,包括查询语句、DML 中的查询子句,优化器基于代价模型实现,生成一颗查询代价最低的查询计划树。此时,优化器已经通过自行计算或参考 HINT 提示决策出以何种方式执行,例如是否选择向量化计算加速能力等。
动态重写(TRANSFORM)阶段,根据统计信息、动态的查询计划进行等价变换。
执行(EXECUTE)阶段,执行器根据计划树进行迭代执行,分为普通模式执行。
计划树的叶子节点通常是扫描算子,扫描算子需要从存储层获取数据,此时会产生 IO。计划树的中间的算子很多情况下(例如分组、排序、去重等操作)需要缓存下层算子的结果集,此类算子称为物化算子,缓存结果集的区域称为物化区。内存不足时,物化算子会将一部分数据换出到存储介质上,此时也会产生 IO。
#DML SQL 处理
DML 采用游标技术完成对数据的迭代处理操作。
查询操作是根据游标的迭代获取能力,依次获取数据,逐层迭代,通过投影表达式计算,最终将结果集对外呈现。保证读一致性,查询的结果集是查询启动时的数据库快照。
对数据的增/删/改/合并操作,会修改数据库的数据状态,支持读并发的能力,而修改则总是基于数据库的最新状态,需要通过锁控制修改的并发,并通过日志记录修改信息,保证事务的 ACID 特性。
YashanDB 通过减小锁的粒度减小 DML 并发之间出现冲突的可能性,增大事务的吞吐能力。
#DDL SQL 处理
DDL 会修改数据库的元数据状态,执行 DDL 操作前会自动触发之前事务的提交,同时 DDL 会校验是否具备足够的权限、足够的资源来调整元数据。
DDL 操作只会采用硬解析,解析后不进入计划缓存,且优化器不会对 DDL 做多余的优化动作,生成的 DDL 计划主要是解析 DDL 语句所得,DDL 计划会立即执行且执行完后直接丢弃。
建议尽量需要减少 DDL 间的并发、DDL 与 DML 间的并发,提高执行成功率。YashanDB 提供 ONLINE DDL 的能力,少量并发执行对数据库整体性能和吞吐率影响不大。
版权声明: 本文为 InfoQ 作者【YashanDB】的原创文章。
原文链接:【http://xie.infoq.cn/article/cdffd5893dba9b328780bf5c3】。文章转载请联系作者。
评论