数据库SQL SELECT查询的工作原理

作为Web开发人员,虽并非专业的DBA,但我们总是离不开数据库。一般开发员只会应用SQL的四条经典语句:select,insert,delete,update。以至于从来没有研究过它们的工作原理,在这里我们说一说select在数据库中的工作原理。

B/S架构中最经典的话题无非于三层架构,可以大概分为数据层,业务逻辑层和表示层,而数据层的作用一般都是和数据库交互,例如查询记录。我们经常是写好查询SQL,然后调用程序执行SQL。但是它内部的工作流程是怎样的呢?先做哪一步,然后做哪一步等,我想还有大部分朋友和我一样都不一定清楚。

第一步:应用程序把查询SQL语句发给服务器端执行

我们在数据层执行SQL语句时,应用程序会连接到相应的数据库服务器,把SQL语句发送给服务器处理。

第二步:服务器解析请求的SQL语句

1.SQL计划缓存,经常用查询分析器的朋友大概都知道这样一个事实,往往一个查询语句在第一次运行的时候需要执行特别长的时间,但是如果你马上或者在一定时间内运行同样的语句,会在很短的时间内返回查询结果。

原因:

  • 服务器在接收到查询请求后,并不会马上去数据库查询,而是在数据库中的计划缓存中找是否有相对应的执行计划,如果存在,就直接调用已经编译好的执行计划,节省了执行计划的编译时间。
  • 如果所查询的行已经存在于数据缓冲存储区中,就不用查询物理文件了,而是从缓存中取数据,这样从内存中取数据就会比从硬盘上读取数据快很多,提高了查询效率.数据缓冲存储区会在后面提到。

2.如果在SQL计划缓存中没有对应的执行计划,服务器首先会对用户请求的SQL语句进行语法效验,如果有语法错误,服务器会结束查询操作,并用返回相应的错误信息给调用它的应用程序。

注意:此时返回的错误信息中,只会包含基本的语法错误信息,例如select写成selec等,错误信息中如果包含一列表中本没有的列,此时服务器是不会检查出来的,因为只是语法验证,语义是否正确放在下一步进行。

3.语法符合后,就开始验证它的语义是否正确,例如,表名,列名,存储过程等等数据库对象是否真正存在,如果发现有不存在的,就会报错给应用程序,同时结束查询。

4.接下来就是获得对象的解析锁,我们在查询一个表时,首先服务器会对这个对象加锁,这是为了保证数据的统一性,如果不加锁,此时有数据插入,但因为没有加锁的原因,查询已经将这条记录读入,而有的插入会因为事务的失败会回滚,就会形成脏读的现象。

5.接下来就是对数据库用户权限的验证,SQL语句语法,语义都正确,此时并不一定能够得到查询结果,如果数据库用户没有相应的访问权限,服务器会报出权限不足的错误给应用程序,在稍大的项目中,往往一个项目里面会包含好几个数据库连接串,这些数据库用户具有不同的权限,有的是只读权限,有的是只写权限,有的是可读可写,根据不同的操作选取不同的用户来执行,稍微不注意,无论你的SQL语句写的多么完善,完美无缺都没用。

6.解析的最后一步,就是确定最终的执行计划。当语法,语义,权限都验证后,服务器并不会马上给你返回结果,而是会针对你的SQL进行优化,选择不同的查询算法以最高效的形式返回给应用程序。例如在做表联合查询时,服务器会根据开销成本来最终决定采用hashjoin,mergejoin,还是loopjoin,采用哪一个索引会更高效等等,不过它的自动化优化是有限的,要想写出高效的查询SQL还是要优化自己的SQL查询语句。

当确定好执行计划后,就会把这个执行计划保存到SQL计划缓存中,下次在有相同的执行请求时,就直接从计划缓存中取,避免重新编译执行计划。

第三步:语句执行

服务器对SQL语句解析完成后,服务器才会知道这条语句到底代表了什么意思,接下来才会真正的执行SQL语句。

这时分两种情况:

  • 如果查询语句所包含的数据行已经读取到数据缓冲存储区的话,服务器会直接从数据缓冲存储区中读取数据返回给应用程序,避免了从物理文件中读取,提高查询速度。
  • 如果数据行没有在数据缓冲存储区中,则会从物理文件中读取记录返回给应用程序,同时把数据行写入数据缓冲存储区中,供下次使用。

说明:SQL缓存分好几种,这里有兴趣的朋友可以去搜索一下,有时因为缓存的存在,使得我们很难马上看出优化的结果,因为第二次执行因为有缓存的存在,会特别快速,所以一般都是先消除缓存,然后比较优化前后的性能表现,这里有几个常用的方法:

DBCC DROPCLEANBUFFERS

从缓冲池中删除所有清除缓冲区。

DBCC FREEPROCCACHE

从过程缓存中删除所有元素。

DBCC FREESYSTEMCACHE

从所有缓存中释放所有未使用的缓存条目。

SQLServer2005数据库引擎会事先在后台清理未使用的缓存条目,以使内存可用于当前条目。但是,可以使用此命令从所有缓存中手动删除未使用的条目。

这只能基本消除SQL缓存的影响,目前好像没有完全消除缓存的方案,如果大家有,请指教。

结论:只有知道了服务执行应用程序提交的SQL的操作流程才能很好的调试我们的应用程序。

  • 确保SQL语法正确;
  • 确保SQL语义上的正确性,即对象是否存在;
  • 数据库用户是否具有相应的访问权限。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Mysql主从数据库(Master/Slave)同步配置与常见错误

    随着访问量的增加,对于一些比较耗时的数据库读取操作,一般采用将写入与读取操作分开来缓解数据库的压力,数据库引擎一般采用Master/Slave架构.实现mysql服务器的主从配置,可以实现读写分离,另外在主数据库崩溃后可以从备用数据库中恢复数据以不至于网站中断访问.下面简单说下mysql主从服务器配置的过程. 首先需要在同一个局域网内的两台机器(当然也可以用一台机器虚拟两台机器出来),都安装上mysql服务. 主机A: 192.168.1.100 从机B: 192.168.1.101 可以有多台

  • 实现数据库水平切分的两个思路

    引言 随着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大型的互联网应用,每天几十亿的PV无疑对数据库造成了相当高的负载.对于系统的稳定性和扩展性造成了极大的问题.通过数据切分来提高网站性能,横向扩展数据层已经成为架构研发人员首选的方式. 水平切分数据库:可以降低单台机器的负载,同时最大限度的降低了宕机造成的损失: 负载均衡策略:可以降低单台机器的访问负载,降低宕机的可能性: 集群方案:解决了数据库宕机带来的单点数据库不能访问的问题: 读写分离策略:最大限度了提高了

  • mysql数据库太大了如何备份与还原

    命令:mysqlhotcopy 这个命令会在拷贝文件之前会把表锁住,并把数据同步到数据文件中,以避免拷贝到不完整的数据文件,是最安全快捷的备份方法. 命令的使用方法是: mysqlhotcopy -u root -p<rootpass> db1 db2 - dbn <output_dir> 如果需要备份全部数据库,可以加上–regexp=".*"参数. Mysqlhotcopy命令可自动完成数据锁定工作,备份时不用关闭服务器. 它还可以刷新日志,使备份文件和日志

  • MySQL数据库存储过程和事务的区别讲解

    事务是保证多个SQL语句的原子型的,也就是要么一起完成,要么一起不完成 存储过程是把一批SQL语句预编译后放在服务器上,然后可以远程调用 存储过程: 一组为了完成特定功能的SQL语句集(或者自定义数据库操作命令集), 根据传入的参数(也可以没有), 通过简单的调用, 完成比单个SQL语句更复杂的功能, 存储在数据库服务器端,只需要编译过一次之后再次使用都不需要再进行编译:主要对存储的过程进行控制. 优点: 1.执行速度快.尤其对于较为复杂的逻辑,减少了网络流量之间的消耗,另外比较重要的一点是存储

  • 如何合理使用数据库冗余字段的方法

    privot多对多关系的中间表.PT5框架会自动把privot带上. 我们需要隐藏,因为我们不需要privot,而且pritvot也不在我们模型本身,他是中间数据 另外冗余字段,我们有一个表是记录图片的,另一个表是记录商品的. 我们可以在图片你放商品图片里的url 同时商品里放图片id和图片URL 这两个字段是重复的,这就是数据冗余,我们设计数据库是不要出现冗余信息,为啥我们用冗余呢. 主要是为了出于对查询性能的考虑. 我们在这里做了数据冗余,我们就可以减少对图片表的查询,加速查询速度! 不过推

  • MySQL数据库大小写敏感的问题

    在MySQL中,数据库对应数据目录中的目录.数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎).因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性.这说明在大多数Unix中数据库名和表名对大小写敏感,而在Windows中对大小写不敏感. 一个显著的例外情况是Mac OS X,它基于Unix但使用默认文件系统类型(HFS+),对大小写不敏感. 在windows下表名不区分大小写,所以在导入数据后,有可能所有表名均为小写,而再从win导入linux后,在

  • python使用adbapi实现MySQL数据库的异步存储

    之前一直在写有关scrapy爬虫的事情,今天我们看看使用scrapy如何把爬到的数据放在MySQL数据库中保存. 有关python操作MySQL数据库的内容,网上已经有很多内容可以参考了,但都是在同步的操作MySQL数据库.在数据量不大的情况下,这种方法固然可以,但是一旦数据量增长后,MySQL就会出现崩溃的情况,因为网上爬虫的速度要远远高过往数据库中插入数据的速度.为了避免这种情况发生,我们就需要使用异步的方法来存储数据,爬虫与数据存储互不影响. 为了显示方便,我们把程序设计的简单一点,只是爬

  • Mysql数据库的QPS和TPS的意义和计算方法

    在做db基准测试的时候,qps,tps 是衡量数据库性能的关键指标.本文比较了网上的两种计算方式.先来了解一下相关概念. 概念介绍: QPS:Queries Per Second         查询量/秒,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理查询量多少的衡量标准. TPS :  Transactions Per Second   是事务数/秒,是一台数据库服务器在单位时间内处理的事务的个数. 在对数据库的性能监控上经常会提到QPS和TPS这两个名词,下

  • 谈谈数据库的字段设计的几个心得

    数据库的字段设计有很多细节性的技巧,下面将过去在开发中体会到经验整理出来,做个备忘. tinyint 是-128到128 .当属性设置为unsigned的时候.最大值就是255了.现在知道为什么需要设置为unsigned属性了.原来是为了最大限度的使用给予的存储空间.如果不设置.那么假如你的值都是正数的.那么-128这一百多个数字就相当于是浪费了. tinyint会自动设置为tinyint(3). smallint 不设置unsigned的时候,也有3万多的样子. tinytext 就是255个

  • PHP单例模式数据库连接类与页面静态化实现方法

    本文实例讲述了PHP单例模式数据库连接类与页面静态化实现方法.分享给大家供大家参考,具体如下: 数据库test中数据表account内容 单例模式的数据库连接类 db.php <?php //单例模式的数据库连接 class DB { //存储实例的静态成员变量 static public $_instance; //数据库连接静态变量 static public $_connectSource; //连接数据库配置,由于前几天学习了PDO,这里就使用PDO private $_dbConfig

随机推荐