本文译自:http://coding-geek.com/how-databases-work
我们使用数据库,直观感受上是客户端发送一个 SQL,数据库把这个SQL执行一下,查出来数据返回给客户端。但其实SQL在背后被转换,优化,历经许多「磨难」才把结果给取回来。
如上图, 我们看到是从查询处理器里经过解析器,优化器,才进入的执行引擎。
今天我们先来看查询管理器,后面再重点来看查询的优化器是怎样精打细算的。
查询管理器
这一部分是数据库功能体现。在这部分里,会将写得不好的查询转换成可以快速执行代码, 然后执行它,并将结果返回给客户端。这个过程会包含多个步骤:
这部分里,对最后两点我们不会说太多,相对来说他俩没那么关键。
查询解析器
每个SQL语句都会经过分析器去校验语法是否正确。如果你写错了,解析器会拒绝查询。比如你手误,把SELECT 写成了 SLECT,那直接会停止在这儿。
此外,还会检查关键词顺序是否正确。
然后,查询SQL中的表名和列名也会分析,解析器会通过数据库的 metadata 来检查以下内容:
之后会检查查询中对应的表你是否有权限去读或写,毕竟这些访问权限是DBA分配的。
在解析的过程中, 查询SQL 会被转换成数据库的内部表示形式(一般是一棵树)。如果一切 OK,这个转换后的内容会发送给查询「重写器」
查询 Rewriter
在这一步,我们拿到了一个查询的内部表示形式,重写器的目标是要:
重写器会对查询执行一系列已知的规则。如果查询符合某个规则的模式,就会应用这个规则来重写查询。以下是(可选)的规则:
视图合并:如果在查询中使用了视图,那视图将会随着该视图的SQL代码进行转换。
子查询打平:有子查询的查询很难优化,因此重写器将尝试修改查询,甚至删除子查询。
例如
- SELECT PERSON.*
- FROM PERSON
- WHERE PERSON.person_key IN
- (SELECT MAILS.person_key
- FROM MAILS
- WHERE MAILS.mail LIKE 'christophe%');
就会被这条SQL替换
- SELECT PERSON.*
- FROM PERSON, MAILS
- WHERE PERSON.person_key = MAILS.person_key
- and MAILS.mail LIKE 'christophe%';
这个重写后的查询会发送给查询优化器,有趣的来了。
统计
在进入数据库如何优化查询之前,我们需要先谈谈统计信息,因为没有统计信息,数据库就会很傻。如果你不告诉数据库分析自己的数据,它不会这样做,而且会做出错误的假设。
那数据库需要什么信息呢?
我们大概说一下论数据库和操作系统如何存储数据的。他们使用的最小单位称为页或块(默认为4或8 KB)。也就是说,如果你只需要1 KB,也会占一页。如果页面占用8 KB,那就会浪费7 KB。
回到统计来,当你要求数据库获取统计信息时,它会计算这些内容:
这些统计信息会帮助优化器更好的预估查询中磁盘I/O,CPU以及内存的使用。
每一列的统计信息都很重要。比如一个 PERSON 表,需要在 LAST_NAME, FIRST_NAME两列做连接,通过统计,数据库能知道FIRST_NAME这一列共多少个不同的值,LAST_NAME有多少个不同的值。所以数据库会使用LAST_NAME,FIRST_NAME来连接,而不是FIRST_NAME,LAST_NAME,因为LAST_NAME不太可能相同,会少产生数据。大多数情况下,数据库的前两三个字符比较 LAST_NAME就足够了。
当然这些是基本的统计信息,你也可以让数据库计算 histograms 这种更高阶的统计数据。最常使用的值,质量等等,通过这些附加信息,可以帮助数据库找到更高效的查询计划,特别是像等值查询,以及范围查询这种。因为数据库已经知道这种情况下有多少条记录。
这些统计信息记录在数据库的元数据中。因此也是需要花时间不断更新的。这也是为啥在大多数数据库里他都不自动更新。
后面的文章,会描述查询优化器的一些细节。
读完这部分之后,扩展阅读:
本文转载自微信公众号「 Tomcat那些事儿」,可以通过以下二维码关注。转载本文请联系 Tomcat那些事儿公众号。
mysql提供的模式匹配的其他类型是使用扩展正则表达式。 当你对这类模式进行匹配...
1.小程序端代码示例 my.getPhoneNumber({ success: (res) = { let encryptedData...
PHP+Mysql简单实现了图书购物车 本文主要讲述如何通过PHP+HTML简单实现图书购物...
有许多命令行选手在linux下开发的时候会经常遇到一个问题,无论是svn还是git,提...
vscode怎么浏览器打开html预览?这里大家可以通过安装open in browser插件解决。...
1. 始终在 `v-for` 中使用 `:key` 在需要操纵数据时,将key属性与v-for指令一起...
步骤: 1、新建一个空文件,文件名为hhhh 2、初始化 git init 3、自己要与origin...
官网连接 https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/...
图片来自 Pexels 突然电话响了起来,一看是我们的一个开发同学,顿时紧张了起来...
Java HashMap removeNode 方法 分析 源码分析仓库 https://github.com/HANXU2018...