查询管理器:
查询管理器是数据库的关键,在这里将对查询进行检查、优化、执行,并将查询结果返回给客户端。
Fig. 10
一般有以下步骤:
- 查询解析,检查查询是否合法(一般是语法);
- 重写查询,去除不必要操作,执行预处理;
- 查询被优化,以期提高性能;再转换为可执行的数据存取计划;
- 编译存取计划,并执行。
以下重点分析前面三个步骤。
查询解析:
在该过程一般检查SQL语法、查询表是否存在、列是否存在、类型是否正确、运算是否正确,然后检查用户是否对表有操作权限,解析过程中,会将SQL转化为数据库内部表示形式,解析通过,内部表示形式将传给查询重写。
查询重写:
查询重写目的是对查询做优化,去除不必要操作,帮助优化器选择最优查询方案。
重写器会根据已有的查询规则匹配当前查询,如果匹配到,则按照相应规则查询。以下简述部分规则:
- View merging:如果查询中使用了视图,则视图将会被视图查询语句替换。
-
子查询:子查询较难优化,重写器会用一个易于优化的子查询替换原来的子查询。
如:
SELECT PERSON.*
FROM PERSON
WHERE PERSON.person_key IN
(SELECT MAILS.person_key
FROM MAILS
WHERE MAILS.mail LIKE 'christophe%');
会被替换为:
SELECT PERSON.*
FROM PERSON, MAILS
WHERE PERSON.person_key = MAILS.person_key
and MAILS.mail LIKE 'christophe%';
- 删除不必要操作:如查询中有distinct,但字段中已有unique约束,则distinct将会被删除。
- 常量运算赋值: 如果你写了一个语句,其中需要一个运算,那这个运算也许会在"查询重写"中完成。比如, WHERE AGE > 10+2 会被转换成 WHERE AGE > 12, 或者 TODATE("某个日期")会被转换成日期格式的数据。
统计:
统计是数据库查询与优化的重要前提,如果没有有效的统计信息就不必谈数据库有效查询了。数据库执行统计时会收集一些普通与高级统计信息,普通的统计信息一般有:
- 一个表的行数以及该表占用的page数(Page是数据库与操作系统存储数据的最小单元,也可称为block,默认4或8Kb,即1Kb的数据也会占用一个大小为8Kb的page,而造成7Kb空间浪费。
-
对表的列:
- 所有不同的取值
- 数据值的长度(最小,最大,平均)
- 数据的范围(最小,最大,平均)
- 表上的索引信息
这些统计信息可以优化某个查询时,判断I/O,CPU以及内存的使用。比如联合查询a,b两个字段,在统计到a有1000个值而b有1M值的时候,数据库会做b,a连接而不会做a,b连接(即让a做查询驱动)。
数据库高级统计信息(称为柱状图),可知表中每列的取值情况,如:最高频取值,不同值的比例等,这些统计信息对等值选取(=)或范围(<,>)选取很有用。这些统计信息放在数据库的系统表中,如oracle中的DBA_TABLES,DBA_TAB_COLUMNS,postgres中的pg_states等。
统计信息需要实时更新,比如查询实际1M的行,因没有实时更新统计信息数据库以为只有500,这显然很尴尬。但统计有一个缺点就是很耗费资源,尤其对像亿万级别的数据库而言。故在实际情况下,一般会只统计基本信息或者对数据进行抽样统计。