#SQL
# SQL简介
结构化查询语言(SQL,Structured Query Language)是一种关系型数据库的操作语言,用于数据存取、数据查询、数据处理和关系型数据库系统管理。SQL提供一个操作关系型数据库的接口,且内置了安全访问机制检查。所有应用都可以使用SQL语句访问YashanDB数据库中的数据。
SQL语言一种非过程化的声明性语言,只需描述语句的目的(做什么样的数据操作),无需提供实现的过程。因此,YashanDB在处理SQL时,需要先使用SQL编译器生成基于SQL目标的过程结构-执行计划,再操作数据库,最终执行算子得到对应结果集。
SQL语言的存在可以帮助用户只需聚焦于数据处理本身无需过于关注实现过程,例如统计一个公司所有部门下转正员工的平均工资,SQL语句示例如下:
SELECT DEPARTMENT_ID,AVG(SALARY) FROM EMPLOYEE E GROUP BY DEPARTMENT_ID HAVING E.ATTR = "已转正" ORDER BY DEPARTMENT_ID
该查询语句中,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是表示列名的标识符。
CREATE TABLE EMPLOYEE(DEPARTMENT_ID INTEGER, SALARY NUMBER);
绑定参数
指在SQL语句中为了减少重复、相似的SQL操作,节约编译时间,将出于相似目的SQL操作中变化的部分用绑定参数代替。
例如,如下DML语句中,符号“?”表示可以绑定不同值的绑定参数。
SELECT * FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = ? AND E.SALARY >= ?;
字面量
指在SQL语句中直接通过组成SQL语句的字符串来表示具体的数值、字符串和特定类型的常量。当字面量要表示字符串时,需要使用单引号
''
包围进行转义。例如,如下DML语句中,字符串
'10'
,'20000'
表示进行特定列筛选的数值。SELECT * FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = '10' AND E.SALARY >= '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的能力,少量并发执行对数据库整体性能和吞吐率影响不大。