1110MySQL select实现原理
转自http://www.jianshu.com/p/NsWbRv
工作中需要借鉴MySQL对于select的具体实现,在网上搜了很久,几乎都是介绍原理的,对于实现细节都没有介绍,无奈之下只得自己对着源码gdb。结合以前对于sql解析的了解,对mysql select的具体实现有了大致的了解,总结一下。
如果要gdb单步调试,需要在编译MySQl时加上debug选项,参见这篇博客.编译好以后就可以用gdb启动了。如果希望mysql运行时有日志输出,可以指定输出文件的路径和日志类型:--debug=d,info,error,query,enter,general,where:O,/tmp/mysqld.trace
日志对MySQl内部逻辑的了解还是挺有用的。
MySQl在设计时,采用了这样的思路:针对主要应用场景选择一个或几个性能优异的核心算法作为引擎,然后努力将一些非主要应用场景作为该算法的特例或变种植入到引擎当中。具体而言,MySQL的select查询中,核心功能就是JOIN查询,因此在设计时,核心实现JOIN功能,对于其它功能,都通过转换为JOIN来实现。
比如select id, name from student;
,MySQL在执行时,也会转换为JOIN来操作。
用gdb单步跟踪后可以看出MySQL的执行过程大致如下:
- 收到请求后分配线程处理;
- sql解析,MySQL解析完sql以后,会生成很多item类。item类是sql解析和执行中最重要的类之一,对于它的介绍可以参见这里。
- 执行sql,可以看到
JOIN::exec
,MySQL是将任何select都转换为JOIN来处理的。
以sql:select A.id, B.score from student A left join subject B on A.id=B.id where A.age > 10 and B.score > 60;
为例来说明上面的步骤3的具体过程。
首先,MySQL在执行sql之前,会对sql进行优化处理,具体是在JOIN::optimise
函数中完成。MySQL针对JOIN的优化做的非常好,因此才会将其他操作都转换为性能实现的非常好的JOIN操作。对于上面的sql,MySQL在执行时,会将join的key也转换为一个where条件:A.id=B.id
来执行,那么经过处理后,上面的sql就有了3个where条件:
A.age > 10
;A.id = B.id
;B.score > 60
;
预处理完以后开始执行,即JOIN::exec
函数,首先会调用send_fields
函数,将最终结果的信息返回,然后调用do_select
。MySQL的join是采用nested loop join,可以参见这篇博客。在do_select
函数中,通过调用sub_select
函数来具体实现join功能。
在上面的例子中,需要完成2个join:先join表A,再join表B(这里请注意,不是涉及几个表,就需要join几个表,MySQL的join优化还是挺强大的,具体解释见后)。在MySQL进行sql解析时,会生成一个需要join的表的list,后面会挨个对该list的表进行join操作。
继续gdb,在sub_select
函数中,可以看到这样一行代码:(*join_tab->read_first_record)(join_tab)
这个就是读取表A的第一行结果,可以看join_tab
里面的信息有表A的名字。接下来就是很关键的一个函数:evaluate_join_record
,这个函数主要做2件事:
- 将当前已经拿到的信息进行where条件计算,判断是否需要继续往下走;
- 递归JOIN;
还是以上面的sql为例,首先执行第一个join,此时会遍历表A的每一行结果,每遍历一个结果,会进行where条件的判断。这里需要注意:当前的where条件判断只会判断已经读出来的列,由于此时只读出来表A的数据,因此现在只能对第一个where条件,即A.age > 10
进行判断,如果满足,则递归调用join:sql_select.cc: 11037 rc=(*join_tab->next_select)(join, join_tab+1, 0);
,这里的next_select函数就是sub_select
,MySQL就是这样来实现递归操作的。如果不满足,则不会递归join,而是继续到下一行数据,从而达到剪枝的目的。
继续跟下去,此时通过上面的next_select
递归的又调用到sub_select
上,同样会走上面的逻辑,即先read_first_record
,然后evaluate_join_record
,这里由于表A和表B的数据都有了,于是可以对上面后面2个where条件:A.id = B.id
和B.score > 60
进行判断了。到此,所有的where条件都已经判断完毕,如果当前行对3个where条件都满足,就可以将结果输出。
以上就是select实现的大体过程,主要有2点,一个是join是采用递归实现的,另一个是每读一个表的数据,会将当前的where条件进行计算,剪枝。还有一个细节没有提到:MySQL是如何进行where条件判断的?或者说,MySQL是如何进行表达式计算的?
答案就是前面提到的item类。当MySQL在解析时,会将sql解析为很多item,同时也会建立各个item之间的关系。对于表达式,会生成一棵语法树。比如表达式:B.score > 60
,此时会生成3个item:B.score
、>
和60
,其中B.score
和60
分别是>
的左右孩子,这样,求表达式的值时,就是求>
的val_int()
,然后就会递归的调用左右子树的val_int()
,再做比较判断即可。
还有一个问题:如何求B.score
的val_int()
?对于此问题的答案我没有具体看过,根据之前一个同事的sql实现方式,我是这样推测的:B.score
是数据表中的真实值,因此它的值肯定是通过去表中获取。在item类中,有一个函数:fix_field
,它是用于告诉外界,去哪里获取此item的值,往往在sql执行的预处理阶段调用。于是在预处理时,告诉该item去某个固定buffer读取结果,同时,每当从表中读出一行数据时,将该数据保存在该buffer中,这样就可以将两者关联起来。这个部分纯属个人推测,感兴趣的同学可以自己根据源码看看。
再回到之前提到的一点,如果我们将sql稍微改一下:select A.id, B.score from student A left join subject B on A.id=B.id where B.score > 60;
,即去掉第一个where条件,此时会发生什么?
答案是,MySQL会做一个优化,将sql转换为select B.id, B.score from subject B where B.score > 60
,这样就不需要A同B join的逻辑了。实际上最开始我在gdb时就用的这条sql,结果死活看不到递归调用sub_select
的场景,还以为原理不对,后来才发现是MySQL优化捣的乱。
-- SELECT 语句:针对a表过滤放在where里面,针对b表过滤放在on,最好的效果
SELECT * FROM a
JOIN b ON a.id=b.ref_id AND b.age>10
WHERE a.sex='男'
1110MySQL select实现原理的更多相关文章
- 【转】Select模型原理
Select模型原理利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫 ...
- Select模型原理
Select模型原理 利用select函数,推断套接字上是否存在数据,或者是否能向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据, ...
- select查询原理
原文:select查询原理 我并非专业DBA,但做为B/S架构的开发人员,总是离不开数据库,一般开发员只会应用SQL的四条经典语句:select ,insert,delete,update.但是我从来 ...
- select用法&原理详解(源码剖析)(转)
今天遇到了在select()前后fd_set的变化问题,查了好久终于找到一个有用的帖子了,很赞,很详细!!原文链接如下: select用法&原理详解(源码剖析) 我的问题是: 如下图示:在se ...
- 深入理解SQL Server数据库Select查询原理(一)
使用SQL Server十年有余,但是一直对其Select查询机制原理一致不明,直到最近有个通讯录表,很简单的一张表(但因简单,所以当时并没有考虑按部门排序问题),结果想查询某个单位所有部门(不重复) ...
- golang的select实现原理剖析
写在最前面 select为golang提供了多路IO复用机制,和其他IO复用一样,用于检测是否有读写事件是否ready. 本文将介绍一下golang的select的用法和实现原理. 实现原理 gola ...
- Oracle 10G select工作原理
数据库查询语句内部执行过程 select * from table 步骤 分析阶段(parse) 1.共享池库高速缓存有没有该语句.如果有直接返回结果. 2.语法分析sql语句是否正确进行下一步分析 ...
- 图解Go select语句原理
Go 的select语句是一种仅能用于channl发送和接收消息的专用语句,此语句运行期间是阻塞的:当select中没有case语句的时候,会阻塞当前的groutine.所以,有人也会说select是 ...
- SQL select查询原理--查询语句执行原则<转>
1.单表查询:根据WHERE条件过滤表中的记录,形成中间表(这个中间表对用户是不可见的):然后根据SELECT的选择列选择相应的列进行返回最终结果. 1)简单的单表查询 SELECT 字段 FROM ...
随机推荐
- Bootstrap学习(3)
Bootstrap 图片 Bootstrap 对图片的支持.Bootstrap 提供了三个可对图片应用简单样式的 class: .img-rounded:添加 border-radius:6px 来 ...
- hadoop2.6---windows下开发环境搭建
一.准备插件 1.自己编译 1.1 安装Ant 官网下载Ant,apache-ant-1.9.6-bin.zip 配置环境变量,新建ANT_HOME,值是E:\apache-ant-1.9.6:PAT ...
- 使用自定义setTimeout和setInterval使之可以传递参数和对象参数
转载自http://www.jb51.net/article/17859.htm /****************************************************** // ...
- 浅谈 Linux 内核无线子系统
浅谈 Linux 内核无线子系统 本文目录 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 L ...
- 在dreamweaver上面制作表格
开始有点犯二,准备一行一行敲,五六十行,人都得敲疯,还容易出错...... 直接从wps复制粘贴到设计里面,立马就出来了,费那事干嘛,哎,工具还是用的不熟
- 用pygame学习初级python(二) 15.5.11
闲得无聊,对第一版的东西做了一些修改,让它更像一个游戏,也具有一些可玩性. 项目的github地址:https://github.com/lfkdsk/BrainHole_pygame 1.人物类进行 ...
- 【原】js实现复制到剪贴板功能,兼容所有浏览器
两天前听了一个H5的分享,会议上有一句话,非常有感触:不是你不能,而是你对自己的要求太低.很简单的一句话,相信很多事情不是大家做不到,真的是对自己的要求太低,如果对自己要求多一点,那么你取得的进步可能 ...
- hdu-5491 The Next(贪心)
题目链接: The Next Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- HQL基础查询语句
HQL基础查询语句 1.使用hql语句检索出Student表中的所有列 //核心代码 @Test public void oneTest() { Query query=session.createQ ...
- 嵌入式Linux驱动学习之路(九)Linux系统调用、驱动程序框架
应用程序通过open read write close 等函数来操作计算机硬件.类似是一个接口. 当应用程序调用这些接口程序时,计算机是如何进入内核的呢?这是经过了系统调用. 实际上当调用接口函数 ...