Written with StackEdit.
查询语句的执行细节
SELECT
SEUDENT.SCO,SNAME,CNAME,GRADE
FROM STUDENT,SC
WHERE STUDENT.SNO=SC.SNO
AND GRADE<60
查询分析
对查询语句进行扫描,词法/语法/语义分析.
语义分析:
- 检查属性是否存在于关系中
- 检查属性是否有二义性(同名的属性在两个表中未指名)
- 前缀补齐
- 检查数据类型
通过数据字典进行检查.
查询检查
检查安全性(权限)
初步静态检查是否影响完整性约束条件
视图转换:视图没有数据.
- 视图消解
- 实体化视图
通过数据字典
查询优化
见单列标题.
- 逻辑优化:关系代数的等价变换:基于启发式规则的/基于代价的
- 物理优化:优化选取I/O方案:基于启发式规则/基于代价/基于语义
查询执行
由代码生成器生成代码的执行树
自顶向下/自底向上
查询算法实例
全表扫描table scan
- 按照物理次序读入M块.
- 检查每个元组,满足则输出
- Loop…
规模大且选择率低时效率低.
索引扫描index scan
B+/hash索引
B+树 See: https://www.jianshu.com/p/1f2560f0e87f
B+ 索引 See: https://blog.csdn.net/cjfeii/article/details/10858721
有索引时进行索引扫描.
读出索引找到符合条件的,定位逻辑地址.
读入满足条件的数据块.
连接操作实例
SELECT * FROM STU,SC WHERE STU.SNO=SC.SNO
嵌套循环
for i in STU:
for j in SC:
if (i.sc==j.sc):
output
数据块为单位进行读写
排序-合并
- Sort by connection(SC)
- Scan&Join
- Until Find the different one
- Loop…
索引连接
通过索引查找连接.
Loop…
Hash Join
用连接属性做hash,用同一个hash函数将两个表的元组散列到hash中.
- 创建hash
- 对元组数少的表进行处理,将元组按照hash分散到hash桶中
- 对另一个表进行处理,按照同一个hash散列.将之前的桶中匹配的hash元组连接起来.
查询优化
总代价=I/O+CPU+内存+通信
最多的是I/O.所以用查询读写的块数作为代价衡量.
Reference: https://blog.csdn.net/TangLinCSDN/article/details/46274351
e.g.
SELECT STU.SNAME
FROM STU,SC
WHERE STU.SNO=SC.SNO AND SC.CNO=2;
对于连接的优化方案:
- 建立广义DKA积并选择相等的向量
- 自然连接(要求两个关系表中进行比较的属性组必须是名称相同的属性组,并且在结果中把重复的属性列去掉)之后选择CNO=2的
- 先选择CNO=2的向量再做自然连接.
优化的方案分析
以块为单位进行代价测定.
Solution Ⅰ
连接
嵌套连接.尽可能多的装载一个表的块,预留一个另一个表的块.然后循环每次读一个另一个表的块.也就是每装载一次A表就要读取一遍B表的块.
为了减少读取B表的遍数,要尽可能装载A表的块.
设A表有
块
条向量,B表有
块
条向量,内存可以存放
块A和1块B.读取总块数为:
连接之后有 条向量,根据新向量的大小确定写出块数.
选择
读入连接后的元组,选择满足要求的记录.
须读入(写出块数).
选取的元组可存放在内存中.(如果选择率过小)
投影
时间忽略不计.
一共
读一遍A-读
遍B-写一遍新块-读一遍新块.
Solution Ⅱ
自然连接和DKA积过程完全相同,仍为 块处理.
选择
中间结果大幅度缩小,只有Sno相等的向量会被读写.
投影
同样忽略不计.
Solution Ⅲ
- 扫一遍A表,选择sno=2的.
- 扫一遍B表,选择SNO=2的.
- 连接,投影输出.
一共耗时仅 .
Conclusion
上面的代数实现的等价优化就是代数优化,其他方式比如扫描方式(全表/索引)的设计就是物理优化.