数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

SQL Server 原理


发布日期:2020年05月08日
 
SQL Server 原理

在讲SQLSERVER内部原理的之前我觉得非常有必要向大家介绍一下SQLSERVER的历史

让我们站在看看计算机数据库业界到底处于什么状态

Oracle已经于月发布了Oracle i(可能中文版在年才来到中国)Oracle i支持用JAVA编写存储过程支持XML支持Linux

SQLSERVER正式发布SQLSERVER重构了整个数据库引擎(相当于重写了SQLSERVER)SQLSERVER第一次完整性的支持了行锁(有没有搞错过去人是怎么使用数据库产品的Oracle就支持行锁另外Oracle就开始研发ERP产品谁说Oracle是ERP门外汉可以参考这个)

看看他们俩的前一个版本如果你入行比较晚(年以后)可能对以下文字更感到惊讶

Oracle发布有了存储过程触发器引用完整性校验分布式事务处理(天哪Oracle才有了这些东西)

SQLSERVER发布SQLSERVER是微软真正意义上的第一个数据库产品(真是爆料大家没想到SQLSERVER才是微软第一个数据库产品那版本之前的是怎么度过的)因为微软和Sybase掰了(Sybase是第一个运行于PC上的C/S数据库产品)微软为了进入数据库产品领域自己又没有经验于是和Sybase一起合作(当时微软是全世界第一大软件公司微软年上市Sybase有产品缺钱微软缺产品有钱于是一拍即合)直到微软也不需要Sybase了(已经学会了数据库技术)Sybase也感觉微软太狼子野心于是合作分裂微软开始自己做自己的数据库

历史说完我们言归正传

很多入门级做管理软件的SQL语句玩的熟练从子查询到Having到交叉表统计SQL都能做出来甚至存储过程能写多行游标自定义函数触发器约束用的眼花缭乱再入点门在SQL查询器中可以使用SQL分析优化索引用SQL Profile可以跟蹤SQL甚至在性能查看器中监测SQLSERVER内存CPU线程I/O的运行状态甚至为自己会使用DBCC而沾沾自喜

你是如此熟悉SQLSERVER又是对SQLSERVER如此陌生

我今天就用架构的角度来给大家分析一下SQLSERVER架构和原理短短一篇博文肯定只能面上的多一些深一层的可能需要连载数篇文章甚至一块大砖头书才能讲完整不过我希望我的博文能够抛砖引玉使大家能从一个过去没有想过的角度去看SQLSERVER

SQLSERVER作为一个数据库产品我个人认为最重要的就是两大块存储引擎和查询引擎

其他的日志事务索引等等都是围绕他们来工作的

SQLSERVER是C/S产品所以一条SQL语句要让SQLSERVER执行必须要传输到SQLSERVER服务器端传输我们当然知道需要NetBEUITCP/IP等等网络传输协议但是光有这些还不行客户端如何发服务器端如何收如何确认发的和收的正确完整如何确实发的和收的已经结束如何发和收能跨越各种网络协议(如UNIX和WINDOWS和NOVELL通讯)如何保证数据安全校验如何保证数据收发是同步还是异步就需要在网络传输协议之上再构造一层协议SQLSERVER既支持IPC机制也支持RPC机制你想想你的管理软件开发平台是否有这一层当然现在的消息服务器已经专业的提供了这一机理可靠的安全的高效的异步的消息压缩消息拆分智能路由集群跨越不同的操作系统不同的编程语言不同的通讯协议不同的硬件平台的消息数据传输可能你过去不了解消息中间件通过这一案例可以知道消息中间件的用途

SQL语句被可靠无误的发送到了服务器端SQLSERVER引擎中第一个模块就来接待这个SQL数据这个模块的名字叫Open Data Services它监听新的连接;清除失败连接;将结果集消息和状态返回给客户端

SQLSERVER客户端和服务器端之间传输数据数据包是有格式的在SQLSERVER中被称为tabular data stream这个数据流是令牌控制客户端和服务器端对话(否则客户端说了N句话服务器端返回N句话没有令牌就混在一起了不知道哪个回答是对应哪个请求的)我们往往不能直接和Open Data Services打交道把数据放进来而是我们必须通过ODBCADO或DBLibrary来发送tabular data stream而SQLSERVER返回的数据结果也是通过这些ODBC之类发回tabular data stream你看看SQLSERVER设计的多巧妙一个通用数据访问接口屏蔽了你和SQLSERVER之间就如同WINDOWS API屏蔽了内核让你无法访问就如同DirectX屏蔽了UI和外设的操控

SQL语句ODBC编码成tabular data streamIPC或RPC网络协议IPC或RPC解码tabular data streamODBCOpen Data Services

Open Data Services监测客户端连接如果并发太多它会创建连接如果服务完它会自己维护连接归入池中在池中保留一段生命期它会自己释放连接如果有的客户端连接中途突然断掉(如客户端重启了)它在侦听后无回应它也会自己整理自己的连接的我们在SQLSERVER线程中看到的连接就是Open Data Services创建的

Open Data Services有了连接(可能是创建的可能是从池里拿出来的池化创建销毁都是非常讲究技能的池化多少上下文资源如何保留池化多长时间什么时候该销毁调度不当就会严重消耗资源)就把SQL接住这时是接到了Open Data Services的读缓沖区里面这个缓沖区为高性能处理数据的SQLSERVER带来一丝喘息机会而就这一丝喘息机会让SQLSERVER可以游刃有余(你的设计有吗?)而Open Data Services有一个写缓沖区SQLSERVER把检索到的数据检索出来就立即放进写缓沖区写缓沖区一满就立即被Open Data Service发走当我过去研究SQLSERVER原理的时候我常常赞歎一个小小的SQLSERVER外围模块都设计如此精妙实在让人佩服我们经常在追求海量数据存储和Cache架构我们却无视我们手边的SQLSERVER

SQL语句放到读缓沖区SQLSERVER的关系引擎就开始工作了它总是在侦听这个读缓沖区

SQL语句遇到的关系引擎的第一个模块就是命令分析器我们在SQL查询分析器中看到的查询分析结果就是它的输出杰作它来构造查询树首先是将你的SQL语句规范化(你想想你写的软件代码输入数据来了什么都不管就直接处理连输入数据校验都没有怎能稳定)否则以后的步骤将不好操作如果你的SQL语句有语法错误这个查询树的构造就无法完成于是中断而要规范一个SQL语句首先要从SQL语法库中抽取SQLSERVER现有支持的各种语法和函数

一旦构造成功关系引擎的第二个模块就是命令优化器来裁剪这棵树一个SQL语句可以生成多种执行和优化的方案(如果你使用过那种SQL优化工具的话你就能理解)SQLSERVER会选择最节省内存CPU利用率I/O次数(I/O是性能优化最要命的地方往往性能就瓶颈在I/O上)的那一种方案优化器会根据每张表的数据统计(有时候你为了性能优化必须定时期同步更新一下统计否则优化就会有误差)而且优化器也会根据查询树去选择合适的索引(如果使用索引代价大它会自动选择全表扫描)优化器也会根据查询树知道先取哪些表的数据然后再内存中如何合并数据以得到你想要的结果(有时候想想优化器真伟大你一个SQL过去它需要在极短的时间内做多少事啊为了能在极短时间内确定一个相对优化的方案它也不可能穷举所有可能的方案所以我们做海量数据优化的时候往往评估多种方案然后修改自己的SQL语句以符合产生最优的方案)

规范化优化完SQL语句就要产生执行计划了SQL管理器负责执行计划的产生因为你发过来的SQL语句可能是一个SELECT也可能是一个INSERT或UPDATE即使SELECT也面临着用户权限的限制(你如果设置过某一个SQLSERVER用户的对象权限和列权限你就会明白)而INSERT之类更新语句又会涉及到权限默认值约束表达式主外键触发器一个优化完的SQL具体要真正让SQLSERVER从内存或硬盘上把数据找出来或者更新回去需要很多细节的步骤

查询执行器来负责SQL的执行因为SQL的执行要涉及到事务等待CPU调度内存页失效影响I/O存取影响所以查询执行器会协调很多其他模块但各个模块来负责处理而查询执行器并不真正全部包办否则让事务管理器锁管理器索引管理器页面文件管理器缓沖管理器行管理器日志管理器干吗去

查询执行器是查询引擎的最后一个模块接下来的模块都属于存储引擎的范畴所以从上看查询引擎最主要是构造SQL查询树优化裁剪SQL查询树根据查询树产生执行计划然后协调执行查询树把结果返回去

而真正要把数据取出来或存进去就需要存储引擎来工作了

首先根据执行计划要存取哪些数据页和索引页这就是访问方法管理器(access methods manager)要做的事情但其实真要打开这些页还不是访问方法管理器自己要亲手干的

亲手干这个活的是一个叫“缓沖区管理器”的模块因为在硬盘上的数据是不可能计算处理的必须要在内存中才能让CPU来计算所以要存取那些数据页和索引页就通知让缓沖区管理器来做如果数据没有在内存中就让缓沖区管理器来读入如果数据已经在内存中了缓沖区管理器只有返回即可这个过程是被缓沖区管理器来屏蔽的对于访问方法管理器是透明的大家可不要以为访问方法管理器啥事不做只是一个发布调度命令的这可错怪了它因为SQLSERVER要保证高速处理必须预先预测好哪些数据页和索引页要处理不能人家缓沖管理器已经处理完你访问方法管理器才计算下一步将要处理的页面要知道这些管理器可是不分哪个用户来处理的如果接受来自多个并发的用户发来各种各样的数据处理请求你怎么能预测到哪些数据页和索引页要处理呢?这就需要一个统一的调度而且这个统一的调度也影响着缓沖区管理器你不能请求一个大数据缓沖区管理器这才火烧屁股才扩大缓沖区然后装载数据那样流水线就停下了缓沖区管理器必须预先知道将在不久要有一个大数据所以在并行运算的时候就有独立线程来扩展了缓沖区因为扩大缓沖区还和操作系统有关你要扩大缓沖区正好遇到WINDOWS页面失效就涉及到你的虚拟文件的变化而页面失效又会影响CPU和I/O所以页面失效是一个性能影响很大的问题而提高命中率是我们性能优化一直努力的重点如果数据长时间不用缓沖区管理器就要让这块内存数据过期可以被新的数据覆盖否则缓沖区老加载不卸载也不行再说有些数据已经被更新了你数据老化了不重新读入你的数据就引起读错误了

我们知道数据页包含数据行索引页包含索引行数据行就由行管理器来控制而索引行由索引管理器来负责

而单行上的检索修改执行又被事务管理器和锁管理器影响着事务有显性事务和隐性事务两种而锁又有共享锁排它锁更新锁意向锁而锁还分为行锁页锁表锁数据库锁而锁又有死锁的可能性锁的不同加上事务的影响这个行是否能读能修改能怎样的读(读一致还是髒读)是等待事务和锁还是可以进行就受了很多影响因为一张数据页上放的行是有限的尤其还有填充度的影响(如填充度为%就这个数据页面只能填充%就必须分页以防以后有数据插入的时候就非常影响数据插页这也是性能影响比较大尤其在插入数据比较多的情况下)SQLSERVER的一张数据页默认是K除去填充度和数据头也没有多少可存储的数据了这就是为了关系型数据库都劝阻大家要小表大数据也就是说列要少列要短频繁访问的列要在前数据可以海量如果行长了你想要检索和更新多少数据页这需要多少页面调度面临着页面失效和锁机制的影响而且大文本和可变行都是指针存储需要跳转查找更浪费了不少时间

而索引管理器最主要在维护着索引B树没有索引页我们就要做全表扫描了那需要载入多少数据页而且还要逐行扫描如果遇上事务和更新锁就更有问题所以索引是非常重要的而一个表可以建立很多索引索引能直接找到所需要的行而无须全表扫描但是你的索引如果仅仅是男女或者你的索引涉及到可变行都对索引不利索引不宜建立多否则维护索引页的成本和消耗也非常多索引页更要涉及到插页拆页频繁改动涉及到索引的字段会让索引页剧烈变动尤其数据量越大影响越大我就不在这里讲解如何利用索引优化SQL了否则一本书也讲不完

数据不断存取数据不断被维护载入内存或从内存中写入硬盘其实都是惰性写入器在照顾惰性写入器来定期扫描老化数据让硬盘和内存中的数据是一致的有这个惰性写入器就有了内存和硬盘的差异时间窗就有可能出现异常一旦服务器突然断电没有来得及写会磁盘的怎么办也也涉及到另一个模块日志管理器日志管理器利用检查点的机制维护着日志文件在服务器重新启动的时候重写载入日志来把数据恢复到一致性写日志当然要比写数据要容易的多快的多因为写数据要操控内存和硬盘还要注意权限事务所以突然断电你还没反应就来不及了所以日志这种轻量级的方法就可以在恢复一致性上有很好的帮助(当然也丢失数据日志页也没来得及写入硬盘)

讲到这里就剩下事务管理器锁管理器这两个管理器和显性事务隐性事务显性锁隐性锁事务隔离级别锁级别行管理器索引管理器都有很多关系微软有WINDOWS优势又有Jim Gray这样的巨师坐镇(Jim Gray是图灵奖获得者就是此爷提出了数据库事务这一概念盖茨为了让此爷为微软工作而此爷不喜欢雷德蒙天天下雨的天气于是在加州阳光中给此爷单独建了一座研究院)所以在性能上我个人认为SQLSERVER的性能是非常优秀的(你想想一个数据库产品的性能受什么方面的影响)至于业界老称SQLSERVER无法管理海量数据性能不佳我个人感觉都是业界在以讹传讹而尤其中国内地IT业界大部分都是入门级在跟帖嘈杂尤其还有一批更不懂技术的媒体记者或写手

如果真要去说SQLSERVER不行大型海量数据管理必须用某某数据库产品我建议从内部原理内部架构内部实现三个层次诸多方面来剖析到底在不在理

最后就是I/O管理器了我一直不认同SQLSERVER内核中有I/O管理器因为SQLSERVER使用的是和WINDOWS同样的页面调度和页面分配方法何必要自己另创一套呢就如同SQLSERVER把页面硬盘内存线程CPU交给了WINDOWS一样SQLSERVER作为WINDOWS上的一个应用软件应该和WINDOWS上的其他软件一样被WINDOWS管理SQLSERVER又不跨平台无须自己管理

除了SQLSERVER这些内核涉及精妙以外SQLSERVER的外围工具也设计的相当好如SQLSERVER的用户安全性管理方法对象分类(表约束默认索引触发器存储过程视图主键)对象权限方法元数据自管理方法SQL语言SQL查询分析器SQL跟蹤器SQL性能分析器SQL数据库(mastermsdbtempdbmodel)

上一篇:导入SQL Server备份的数据库方法

下一篇:win7下卸载及重新安装sql server2008详细教程