如果再有人问你数据库的原理,把这篇文章给他( 七 )


如果一切正常,内部表示被送到查询重写器 。
查询重写器在这一步,我们已经有了查询的内部表示,重写器的目标是:

  • 预优化查询
  • 避免不必要的运算
  • 帮助优化器找到合理的最佳解决方案
重写器按照一系列已知的规则对查询执行检测 。如果查询匹配一种模式的规则,查询就会按照这条规则来重写 。下面是(可选)规则的非详尽的列表:
  • 视图合并:如果你在查询中使用视图,视图就会转换为它的 SQL 代码 。
  • 子查询扁平化:子查询是很难优化的,因此重写器会尝试移除子查询
例如:
MySQL
如果再有人问你数据库的原理,把这篇文章给他

文章插图
 
会转换为:
MySQL
如果再有人问你数据库的原理,把这篇文章给他

文章插图
 
  • 去除不必要的运算符:比如,如果你用了 DISTINCT,而其实你有 UNIQUE 约束(这本身就防止了数据出现重复),那么 DISTINCT 关键字就被去掉了 。
  • 排除冗余的联接:如果相同的 JOIN 条件出现两次,比如隐藏在视图中的 JOIN 条件,或者由于传递性产生的无用 JOIN,都会被消除 。
  • 常数计算赋值:如果你的查询需要计算,那么在重写过程中计算会执行一次 。比如 WHERE AGE > 10+2 会转换为 WHERE AGE > 12,TODATE(“日期字符串”) 会转换为 datetime 格式的日期值 。
  • (高级)分区裁剪(Partition Pruning):如果你用了分区表,重写器能够找到需要使用的分区 。
  • (高级)物化视图重写(Materialized view rewrite):如果你有个物化视图匹配查询谓词的一个子集,重写器将检查视图是否最新并修改查询,令查询使用物化视图而不是原始表 。
  • (高级)自定义规则:如果你有自定义规则来修改查询(就像 Oracle policy),重写器就会执行这些规则 。
  • (高级)OLAP转换:分析/加窗 函数,星形联接,ROLLUP 函数……都会发生转换(但我不确定这是由重写器还是优化器来完成,因为两个进程联系很紧,必须看是什么数据库) 。
【物化视图,谓词,predicate,条件表达式的求值返回真或假的过程】
重写后的查询接着送到优化器,这时候好玩的就开始了 。
统计研究数据库如何优化查询之前我们需要谈谈统计,因为没有统计的数据库是愚蠢的 。除非你明确指示,数据库是不会分析自己的数据的 。没有分析会导致数据库做出(非常)糟糕的假设 。
但是,数据库需要什么类型的信息呢?
我必须(简要地)谈谈数据库和操作系统如何保存数据 。两者使用的最小单位叫做页或块(默认 4 或 8 KB) 。这就是说如果你仅需要 1KB,也会占用一个页 。要是页的大小为 8KB,你就浪费了 7KB 。
回来继续讲统计! 当你要求数据库收集统计信息,数据库会计算下列值:
  • 表中行和页的数量
  • 表中每个列中的:
    唯一值
    数据长度(最小,最大,平均)
    数据范围(最小,最大,平均)
  • 表的索引信息
这些统计信息会帮助优化器估计查询所需的磁盘 I/O、CPU、和内存使用
对每个列的统计非常重要 。比如,如果一个表 PERSON 需要联接 2 个列: LAST_NAME, FIRST_NAME 。根据统计信息,数据库知道FIRST_NAME只有 1,000 个不同的值,LAST_NAME 有 1,000,000 个不同的值 。因此,数据库就会按照 LAST_NAME, FIRST_NAME 联接 。因为 LAST_NAME 不大可能重复,多数情况下比较 LAST_NAME 的头 2 、 3 个字符就够了,这将大大减少比较的次数 。
不过,这些只是基本的统计 。你可以让数据库做一种高级统计,叫直方图 。直方图是列值分布情况的统计信息 。例如:
  • 出现最频繁的值
  • 分位数 【译者注:http://baike.baidu.com/view/1323572.htm】
这些额外的统计会帮助数据库找到更佳的查询计划,尤其是对于等式谓词(例如: WHERE AGE = 18 )或范围谓词(例如: WHERE AGE > 10 and AGE < 40),因为数据库可以更好的了解这些谓词相关的数字类型数据行(注:这个概念的技术名称叫选择率) 。
统计信息保存在数据库元数据内,例如(非分区)表的统计信息位置:
  • Oracle: USER / ALL / DBA_TABLES 和 USER / ALL / DBA_TAB_COLUMNS
  • DB2: SYSCAT.TABLES 和 SYSCAT.COLUMNS
统计信息必须及时更新 。如果一个表有 1,000,000 行而数据库认为它只有 500 行,没有比这更糟糕的了 。统计唯一的不利之处是需要时间来计算,这就是为什么数据库大多默认情况下不会自动计算统计信息 。数据达到百万级时统计会变得困难,这时候,你可以选择仅做基本统计或者在一个数据库样本上执行统计 。


推荐阅读