一个数据库SQL查询的数次轮回
本文译自:http://coding-geek.com/how-databases-work
我们使用数据库,直观感受上是客户端发送一个 SQL,数据库把这个SQL执行一下,查出来数据返回给客户端。但其实SQL在背后被转换,优化,历经许多「磨难」才把结果给取回来。
数据库是咋工作的?(一)
如上图, 我们看到是从查询处理器里经过解析器,优化器,才进入的执行引擎。
今天我们先来看查询管理器,后面再重点来看查询的优化器是怎样精打细算的。
查询管理器
这一部分是数据库功能体现。在这部分里,会将写得不好的查询转换成可以快速执行代码, 然后执行它,并将结果返回给客户端。这个过程会包含多个步骤:
首先解析查询是否是合法的
然后会将查询重写,去除没用的操作符,并做一些预优化
对查询优化以提升性能,将查询转换成执行和数据访问计划
编译查询计划
执行
这部分里,对最后两点我们不会说太多,相对来说他俩没那么关键。
查询解析器
每个SQL语句都会经过分析器去校验语法是否正确。如果你写错了,解析器会拒绝查询。比如你手误,把SELECT 写成了 SLECT,那直接会停止在这儿。
此外,还会检查关键词顺序是否正确。
然后,查询SQL中的表名和列名也会分析,解析器会通过数据库的 metadata 来检查以下内容:
表是否存在
表中对应的查询字段是否存在
对应的操作符是不是能作用在指定的列上(比如不能把一个数字和字符串比大小,也不能给一个integer用substring)
之后会检查查询中对应的表你是否有权限去读或写,毕竟这些访问权限是DBA分配的。
在解析的过程中, 查询SQL 会被转换成数据库的内部表示形式(一般是一棵树)。如果一切 OK,这个转换后的内容会发送给查询「重写器」
查询 Rewriter
在这一步,我们拿到了一个查询的内部表示形式,重写器的目标是要:
对查询做预优化
避免无用的操作
帮助优化器发现最佳方案
重写器会对查询执行一系列已知的规则。如果查询符合某个规则的模式,就会应用这个规则来重写查询。以下是(可选)的规则:
视图合并:如果在查询中使用了视图,那视图将会随着该视图的SQL代码进行转换。
子查询打平:有子查询的查询很难优化,因此重写器将尝试修改查询,甚至删除子查询。
例如
SELECT PERSON.*FROM PERSONWHERE PERSON.person_key IN(SELECT MAILS.person_keyFROM MAILSWHERE MAILS.mail LIKE 'christophe%');
就会被这条SQL替换
SELECT PERSON.*FROM PERSON, MAILSWHERE PERSON.person_key = MAILS.person_keyand MAILS.mail LIKE 'christophe%';
去除无用的操作符:如果你用了DISTINCT,但你已经有一个UNIQUE约束以保证数据唯一,那DISTINCT关键字就会被删除。
消除多余的连接:如果你有两次相同的连接条件,因为一个连接条件被隐藏在视图中,或者由于传递性而导致无用的连接,则将其删除。
持续的算术评估:如果查询是需要计算的内容,那么在重写过程中将对其进行一次计算。比如,把
WHERE AGE> 10 + 2
转换为WHERE AGE> 12
,然后将TODATE(“ 日期”)
转换为datetime格式的日期(高级)分区修正:如果你使用了分区表,重写器可以找到要使用的分区。
(高级)实例化视图重写:如果已经有了和查询子集匹配的实例化视图,重写器会检查该视图是否是最新视图,并修改查询使用实例化视图而不是原始表。
(高级)自定义规则:如果你创建了重写查询的自定义规则,那重写器会执行这些规则(高级)Olap转换:分析/窗口函数,星型连接,汇总…也都会进行转换(但是具体是由重写器还是优化器完成的取决于数据库,因为这两个过程邻近)。
这个重写后的查询会发送给查询优化器,有趣的来了。
统计
在进入数据库如何优化查询之前,我们需要先谈谈统计信息,因为没有统计信息,数据库就会很傻。如果你不告诉数据库分析自己的数据,它不会这样做,而且会做出错误的假设。
那数据库需要什么信息呢?
我们大概说一下论数据库和操作系统如何存储数据的。他们使用的最小单位称为页或块(默认为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 这种更高阶的统计数据。最常使用的值,质量等等,通过这些附加信息,可以帮助数据库找到更高效的查询计划,特别是像等值查询,以及范围查询这种。因为数据库已经知道这种情况下有多少条记录。
这些统计信息记录在数据库的元数据中。因此也是需要花时间不断更新的。这也是为啥在大多数数据库里他都不自动更新。
后面的文章,会描述查询优化器的一些细节。
读完这部分之后,扩展阅读:
The initial research paper (1979) on cost based optimization: Access Path Selection in a Relational Database Management System. This article is only 12 pages and understandable with an average level in computer science.
A very good and in-depth presentation on how DB2 9.X optimizes queries here
A very good presentation on how PostgreSQL optimizes queries here. It’s the most accessible document since it’s more a presentation on “let’s see what query plans PostgreSQL gives in these situations“ than a “let’s see the algorithms used by PostgreSQL”.
The official SQLite documentation about optimization. It’s “easy” to read because SQLite uses simple rules. Moreover, it’s the only official documentation that really explains how it works.
A good presentation on how SQL Server 2005 optimizes queries here
A white paper about optimization in Oracle 12c here
2 theoretical courses on query optimization from the authors of the book “DATABASE SYSTEM CONCEPTS”here and there. A good read that focuses on disk I/O cost but a good level in CS is required.
Another theoretical course that I find more accessible but that only focuses on join operators and disk I/O.
相关阅读
MySQL: 喂,别走,听我解释一下好吗?
数据库是咋工作的?(一)
凭什么让日志先写?
Java七武器系列长生剑 -- Java虚拟机的显微镜 Serviceability Agent
Java七武器系列霸王枪 -- 线程状态分析 jstack
Java七武器系列孔雀翎-- 问题诊断神器BTrace
嵌套事务、挂起事务,Spring 是怎样给事务又实现传播特性的?
怎样阅读源代码?
如果你觉也还可以,来个在看或转发吧,多谢!
源码|实战|成长|职场
这里是「Tomcat那些事儿」
请留下你的足迹
我们一起「终身成长」
一个数据库SQL查询的数次轮回相关推荐
- Python学习日志16 - 数据库SQL查询
Python学习日志 RBHGO的主页欢迎关注 温馨提示:创作不易,如有转载,注明出处,感谢配合~ 目录 文章目录 Python学习日志 目录 Python学习日志16课 - 数据库SQL查询 DQL ...
- 视频教程-数据库SQL查询,最佳案例讲解-SQL Server
数据库SQL查询,最佳案例讲解 教学风格独特,以学员视角出发设计课程,难易适度,重点突出,架构清晰,将实战经验融合到教学中.讲授技术同时传递方法.得到广大学员的高度认可. 王进 ¥19.00 立即订阅 ...
- 一个 提高SQL 查询的讨论帖
idn(关键字),产品名称,产品数量... B表,有字段:idn,a_idn(记录A表的关键字),工序,工时... A表与B表是一对多的关系, 我想取到A表的明细及B表相关的总工时 sele aa.* ...
- 数据库SQL查询练习
--重点推荐使用natural join,inner join!!!,尽量避免使用广义的笛卡尔积 --重点推荐使用natural join,inner join!!!,尽量避免使用广义的笛卡尔积 -- ...
- PostgreSQL数据库sql查询如何获取汉字拼音首字母
一.前言 在实际开发过程中,经常会使用模糊查询,根据某个关键字模糊搜索,一般是 name like '%123%' 这样查,但是如果某个关键字用户不记得呢,只知道首字母,又如何模糊查询呢?例如,查询 ...
- [数据库] SQL查询语句表行列转换及一行数据转换成两列
本文主要讲述了SQL查询语句表之间的行列转换,同时也包括如何将一行数据转换成两列数据的方法.子查询的应用.decode函数的用法.希望文章对你有所帮助~ 1.创建数据库表及插入数据 2.子查询统计不同 ...
- WordPress 常用数据库SQL查询语句大全
https://www.wpdaxue.com/wordpress-sql.html 在使用WordPress的过程中,我们少不了要对数据库进行修改操作,比如,更换域名.修改附件目录.批量修改文章内容 ...
- sql server整表查询慢_这里有一个慢 SQL 查询等你来优化
背景 最近工作上遇到一个"神奇"的问题, 或许对大家有帮助, 因此形成本文. 问题大概是, 我有两个表 TableA, TableB, 其中 TableA 表大概百万行级别(存量业 ...
- 一个Spark SQL查询的一生
Spark是时下很火的计算框架,由UC Berkeley AMP Lab研发,并由原班人马创建的Databricks负责商业化相关事务.而SparkSQL则是Spark之上搭建的SQL解决方案,主打交 ...
最新文章
- valgrind——Cachegrind分析CPU的cache命中率、丢失率,用于进行代码优化。
- ISLR线性回归笔记
- java 实现二叉树操作
- [云炬创业基础笔记] 第四章测试16
- 配置审计(Config)配合开启OSS防盗链功能
- 校验用户手机号是否合法
- 100g流量在电脑上可以用多久_三大运营商5G体验方案出炉!100G一个月够不够?...
- finalize方法_final,finally,finalize三者的含义和区别
- 多重背包单调队列优化思路_多重背包问题
- 20179209《Linux内核原理与分析》第一周作业
- c++类的成员函数作回调函数为啥要声明为static的
- 魔兽世界MPQ加载顺序
- Linux搭建FTP服务器
- Android studio基础练习02【监听器实现下拉菜单】
- 这里带你了解IR2104驱动电路
- 计算机无法访问inter,电脑网络提示无Internet访问权限解决办法
- 【微信小程序】条件渲染和列表渲染
- 条码和自动识别的基础知识
- (复现)CVE-2021-21985 Vmware vcenter远程代码执行RCE
- strace命令用法详解