如果一切正常,内部表示被送到查询重写器 。
查询重写器在这一步,我们已经有了查询的内部表示,重写器的目标是:
- 预优化查询
- 避免不必要的运算
- 帮助优化器找到合理的最佳解决方案
- 视图合并:如果你在查询中使用视图,视图就会转换为它的 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 函数……都会发生转换(但我不确定这是由重写器还是优化器来完成,因为两个进程联系很紧,必须看是什么数据库) 。
重写后的查询接着送到优化器,这时候好玩的就开始了 。
统计研究数据库如何优化查询之前我们需要谈谈统计,因为没有统计的数据库是愚蠢的 。除非你明确指示,数据库是不会分析自己的数据的 。没有分析会导致数据库做出(非常)糟糕的假设 。
但是,数据库需要什么类型的信息呢?
我必须(简要地)谈谈数据库和操作系统如何保存数据 。两者使用的最小单位叫做页或块(默认 4 或 8 KB) 。这就是说如果你仅需要 1KB,也会占用一个页 。要是页的大小为 8KB,你就浪费了 7KB 。
回来继续讲统计! 当你要求数据库收集统计信息,数据库会计算下列值:
- 表中行和页的数量
- 表中每个列中的:
唯一值
数据长度(最小,最大,平均)
数据范围(最小,最大,平均)
- 表的索引信息
对每个列的统计非常重要 。比如,如果一个表 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】
- …
统计信息保存在数据库元数据内,例如(非分区)表的统计信息位置:
- Oracle: USER / ALL / DBA_TABLES 和 USER / ALL / DBA_TAB_COLUMNS
- DB2: SYSCAT.TABLES 和 SYSCAT.COLUMNS
推荐阅读
- 如何挑选黑豆
- 不是夫妻合租房犯罪吗
- 医保断缴三个月余额清零?员工可自愿放弃社保?这些谣言别再信了
- 手串颗数大有讲究,千万别戴错了
- “禁止长时间停车”,到底指的是几分钟?交警:最后再说一遍
- 太热了!别再披头散发了,这4款发型够美够清凉
- 没钱还信用卡有什么解决办法
- 信用卡过期卡怎么处理
- 信用卡逾期被注销怎么还钱
- 如何找回抖音私聊记录