在讲SQLSERVER内部原理的之前,我觉得非常有必要向大家介绍一下SQLSERVER的历史。
让我们站在1999年,看看计算机数据库业界到底处于什么状态。
1999年,Oracle已经于1998年9月发布了Oracle 8i(可能中文版在1999年才来到中国)。Oracle 8i支持用JAVA编写存储过程,支持XML,支持Linux。
1999年1月,SQLSERVER7正式发布。SQLSERVER7重构了整个数据库引擎(相当于重写了SQLSERVER)。SQLSERVER第一次完整性的支持了行锁(有没有搞错,过去人是怎么使用数据库产品的。1988年,Oracle6就支持行锁。另外1988年,Oracle就开始研发ERP产品。谁说Oracle是ERP门外汉,可以参考这个)。
看看他们俩的前一个版本。如果你入行比较晚(2000年以后),可能对以下文字更感到惊讶。
1992年,Oracle7发布。有了存储过程、触发器、引用完整性校验、分布式事务处理。(天哪,Oracle7才有了这些东西)。
1995年,SQLSERVER6发布。SQLSERVER6是微软真正意义上的第一个数据库产品(真是爆料,大家没想到SQLSERVER6才是微软第一个数据库产品,那版本6之前的5、4、3、2、1是怎么度过的)。因为1994年,微软和Sybase掰了(Sybase是第一个运行于PC上的C/S数据库产品)。微软为了进入数据库产品领域,自己又没有经验,于是和Sybase一起合作(当时微软是全世界第一大软件公司,微软1986年上市。Sybase有产品,缺钱。微软缺产品,有钱。于是一拍即合)。直到1994年,微软也不需要Sybase了(已经学会了数据库技术),Sybase也感觉微软太狼子野心,于是合作分裂。微软开始自己做自己的数据库。
历史说完。我们言归正传。
很多入门级做管理软件的,SQL语句玩的熟练,从子查询到Having到交叉表统计SQL都能做出来,甚至存储过程能写2000多行,游标、自定义函数、触发器、约束用的眼花缭乱。再入点门,在SQL查询器中可以使用SQL分析优化索引,用SQL Profile可以跟踪SQL,甚至在性能查看器中监测SQLSERVER内存、CPU、线程、I/O的运行状态,甚至为自己会使用DBCC而沾沾自喜。
你是如此熟悉SQLSERVER,又是对SQLSERVER如此陌生。
我今天就用架构的角度来给大家分析一下SQLSERVER架构和原理。短短一篇博文肯定只能面上的多一些,深一层的可能需要连载数篇文章甚至一块大砖头书才能讲完整。不过,我希望我的博文能够抛砖引玉,使大家能从一个过去没有想过的角度去看SQLSERVER。
SQLSERVER,作为一个数据库产品,我个人认为,最重要的就是两大块:存储引擎和查询引擎。
其他的日志、事务、锁、索引等等都是围绕他们来工作的。
SQLSERVER是C/S产品,所以一条SQL语句要让SQLSERVER执行,必须要传输到SQLSERVER服务器端。传输,我们当然知道需要NetBEUI、TCP/IP等等网络传输协议。但是光有这些还不行。客户端如何发,服务器端如何收,如何确认发的和收的正确完整,如何确实发的和收的已经结束,如何发和收能跨越各种网络协议(如UNIX和WINDOWS和NOVELL通讯),如何保证数据安全校验,如何保证数据收发是同步还是异步,就需要在网络传输协议之上再构造一层协议。SQLSERVER既支持IPC机制,也支持RPC机制。你想想你的管理软件开发平台是否有这一层。当然,现在的消息服务器已经专业的提供了这一机理,可靠的、安全的、高效的、异步的、消息压缩、消息拆分、智能路由、集群,跨越不同的操作系统、不同的编程语言、不同的通讯协议、不同的硬件平台的消息数据传输。可能你过去不了解消息中间件,通过这一案例可以知道消息中间件的用途。
SQL语句被可靠无误的发送到了服务器端,SQLSERVER引擎中第一个模块就来接待这个SQL数据。这个模块的名字叫:Open Data Services。它监听新的连接;清除失败连接;将结果集、消息和状态返回给客户端。
SQLSERVER客户端和服务器端之间传输数据,数据包是有格式的。在SQLSERVER中被称为tabular data stream。这个数据流是令牌控制客户端和服务器端对话(否则,客户端说了N句话,服务器端返回N句话,没有令牌就混在一起了,不知道哪个回答是对应哪个请求的)。我们往往不能直接和Open Data Services打交道,把数据放进来。而是我们必须通过ODBC、ADO或DB-Library来发送tabular data stream。而SQLSERVER返回的数据结果,也是通过这些ODBC之类发回tabular data stream。你看看SQLSERVER设计的多巧妙,一个通用数据访问接口屏蔽了你和SQLSERVER之间,就如同WINDOWS API屏蔽了内核让你无法访问,就如同DirectX屏蔽了UI和外设的操控。
SQL语句-ODBC-编码成tabular data stream-IPC或RPC-网络协议-IPC或RPC-解码tabular data stream-ODBC-Open 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要保证高速处理,必须预先预测好哪些数据页和索引页要处理。不能人家缓冲管理器已经处理完,你访问方法管理器才计算下一步将要处理的页面。要知道,这些管理器可是不分哪个用户来处理的。如果接受来自100多个并发的用户,发来各种各样的数据处理请求,你怎么能预测到哪些数据页和索引页要处理呢?这就需要一个统一的调度。而且这个统一的调度也影响着缓冲区管理器。你不能请求一个大数据,缓冲区管理器这才火烧屁股才扩大缓冲区,然后装载数据,那样流水线就停下了。缓冲区管理器必须预先知道将在不久要有一个大数据,所以在并行运算的时候就有独立线程来扩展了缓冲区。因为扩大缓冲区还和操作系统有关。你要扩大缓冲区,正好遇到WINDOWS页面失效,就涉及到你的虚拟文件的变化。而页面失效又会影响CPU和I/O。所以页面失效是一个性能影响很大的问题。而提高命中率是我们性能优化一直努力的重点。如果数据长时间不用,缓冲区管理器就要让这块内存数据过期,可以被新的数据覆盖。否则缓冲区老加载不卸载也不行。再说,有些数据已经被更新了,你数据老化了,不重新读入,你的数据就引起读错误了。
我们知道,数据页包含数据行。索引页包含索引行。数据行就由行管理器来控制。而索引行,由索引管理器来负责。
而单行上的检索、修改、执行,又被事务管理器和锁管理器影响着。事务,有显性事务和隐性事务两种。而锁,又有共享锁、排它锁、更新锁、意向锁。而锁,还分为行锁、页锁、表锁、数据库锁。而锁,又有死锁的可能性。锁的不同,加上事务的影响,这个行是否能读、能修改,能怎样的读(读一致还是脏读),是等待事务和锁,还是可以进行,就受了很多影响。因为一张数据页上放的行是有限的,尤其还有填充度的影响(如填充度为80%,就这个数据页面只能填充80%就必须分页,以防以后有数据插入的时候,就非常影响数据插页,这也是性能影响比较大,尤其在插入数据比较多的情况下)。SQLSERVER的一张数据页默认是64K,除去填充度和数据头,也没有多少可存储的数据了。这就是为了关系型数据库都劝阻大家要小表大数据。也就是说,列要少,列要短,频繁访问的列要在前。数据可以海量。如果行长了,你想要检索和更新多少数据页,这需要多少页面调度,面临着页面失效和锁机制的影响。而且,大文本和可变行,都是指针存储,需要跳转查找,更浪费了不少时间。
而索引管理器,最主要在维护着索引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数据库(master\msdb\tempdb\model)。
分享到:
相关推荐
SQL Server内部原理, 2008 R2 Server
12. `-g memory_to_reserve`:预留一定内存供SQL Server内部使用,单位为MB。 13. `-O`:禁止分布式COM(DCOM),禁用跨服务器查询。 14. `-y error_number`:当遇到指定的错误时,将堆栈跟踪写入错误日志。 ...
- **`-gmemory_to_reserve`**: 指定内存的兆字节数,该内存被保留用于SQL Server内部(进程内)运行的其他应用程序。 - **`-O`**: 指定不需要分布式COM (DCOM),从而禁用异类查询。 - **`-yerror_number`**: 如果...
《Microsoft SQL Server 2008 Internals》一书详细介绍了SQL Server 2008的内部架构和运行原理。全书共分为多个章节,每个章节都涵盖了SQL Server不同方面的内部工作原理和技术细节。以下是一些核心主题: 1. **...
Tripp、Conor Cunningham、Adam Machanic和Ben Nevarez等多位业界知名专家共同撰写,这本书详细揭示了SQL Server 2008的核心架构和工作原理。 书中涵盖了以下几个关键知识点: 1. **存储引擎**:SQL Server 2008...
SQL Server 2005微软官方权威参考书. 公球公认SQL Server 2005 经典著作.. 数据库“铁人”、微软MVP胡百敬先生鼎力推荐 微软SQL Server 总部Principal Group 项目经理朱凌志鼎力推荐 本书详细介绍了数据...
这份"sql server内部学习资料"显然是一份全面的学习资源,涵盖了多种学习材料,包括PPT(演示文稿)、作业答案、演示脚本、SQL项目以及课堂练习,非常适合初学者和进阶者进行系统性的学习。 PPT部分可能包含SQL ...
本书全面探讨了sql server 2008的内部工作原理。全书共分为11章,首先在第1章中详细介绍了sql server 2008... 运行dbcc时,sqlserver在内部检查什么 处理多个并发用户时,如何在5个隔离级别和2个并发模型中做出选择
【SQL Server 2005基础与内部测试详解】 SQL Server 2005是微软公司推出的一款关系型数据库管理系统,广泛应用于企业级数据管理、分析和应用开发。作为北大青鸟S1阶段的学习内容,它涵盖了数据库的基础概念、SQL...
### SQL Server 解析 JSON 字符串方法详解 随着 Web 应用和服务的广泛采用,JSON 成为了一种非常流行的轻量级数据交换格式。在 SQL Server 中处理 JSON 数据变得日益重要,尤其是对于那些需要从非结构化数据源提取...
存储引擎.pdf"将揭示SQL Server 2005的内部工作机制,包括数据存储、索引原理、事务日志管理等核心概念。了解存储引擎的工作原理可以帮助读者优化数据库性能,解决存储和查询效率问题,如合理设计表结构、选择合适的...
SQLSERVER 绿色版 6.5.2.1 源代码的发布,为开发者提供了一次深入了解和学习微软SQL Server数据库系统内部工作原理的机会。这个版本是基于D7编译的,意味着它可能使用的是Delphi 7编程语言进行开发,这是一种流行的...
《专业SQL Server 2012内部原理与故障排查》这本书深入探讨了SQL Server 2012这一数据库管理系统的核心机制及其在实际操作中的问题解决方法。SQL Server 2012是微软公司开发的一款广泛应用于企业级数据管理的重要...
存储引擎》会深入数据库内部,探讨存储引擎的工作原理。这包括了表和索引的物理结构、事务日志管理、锁和并发控制,以及备份与恢复策略。理解存储引擎有助于优化查询性能,合理设计数据库架构,以及解决可能出现的...
在`SQLSERVER 事务日志详解-华仔论坛.doc`文档中,可能会包含以下内容: 1. `fn_dblog`的使用示例,展示如何查询特定事务的历史操作。 2. 对`fn_dblog`返回的关键列的详细解释,帮助理解日志记录的含义。 3. 图形化...
- **内部闩锁使用**:介绍了SQL Server内部用于保护数据结构的闩锁机制。 - **行版本化技术**:探讨了SQL Server如何通过行版本化来支持读取未提交的隔离级别,从而提高并发性能。 ### 故障排查工具与技术 - **...
《SQLServer2005.技术内幕四部曲中文PDF》是一套全面解析SQL Server 2005核心技术的中文教程,包含了T-SQL查询、T-SQL程序设计、存储引擎以及查询、调整和优化四个重要方面。这套书籍旨在帮助IT专业人员深入理解SQL ...