目录
(一)SQL SERVER查询生命周期简介
下图展示的是一个用户从发出请求到得到SQL SERVER响应的流程,即查询生命周期。
(二)基于上图的详解
以下将详细介绍下上图中的每个部件大致的作用,内容经过整理和总结。
1. 协议层
在用户发起对数据库请求后,该请求通过网络接口(SQL SERVER NETWORK INTERFACE,SNI)传到协议层中。SNI是客户端和服务器之间的连接,对于目前已发布的SQL SERVER版本,有以下4种网络协议。
(1)共享内存
它是默认开启的网络协议,也是最快最简单的协议,但是有一定的局限,只能在SQL SERVER所在的本机使用。这也是为什么经常能够在本机连接到SQL SERVER,但是外部极其连不上的原因之一,如果外部访问所需的协议没有开启,外部访问就不能连接SQL SERVER。而且,由于本机使用了共享内存协议,所以不需要做任何配置就可以连上。这个协议仅用于检查连接问题。
(2)TCP/IP
这是互联网上最常用的协议,可让外部访问通过IP地址和端口号(默认1433)来访问SQL。 SERVER。
(3)命名管道
它与TCP/IP类似,不过仅限于局域网访问。该协议默认使用445端口,所以如果使用这种协议,需要确保这个端口的可用性。
(4)VIA
这几乎是个没有用的协议,并且SQL SERVER出现的很多问题都是由于开启了这个服务导致的,可能在后续版本中将会移除(实际上在SQL SERVER 2012已经找不到VIA的影子了),所以不建议用户使用。
小结:
不管使用哪种协议,一旦连接接通。SNI会创建一个安全的TDS端点,用于接收和发送请求。
2. 表格数据流端点
表格数据流端点(Tabular Data Stream Endpoints)起源于Sybase,现在是微软专属的网络协议。一个网络协议一旦连接成功,就会创建一个对应的TDS端点,用于在客户端与服务器之间互传信息。
对于这一步,性能问题可能会出现在把请求的内容转换成SQL SERVER能处理的格式的过程中,如果数据量大,转换开销就高,不管是从外部传入SQL SERVER还是从SQL SERVER输出到外部,都是如此。
3. 命令解析器
在TDS把请求转换成SQL SERVER内部可识别的格式后,首先会传到命令解释器(Command Parser)处,这个组件会检查传入的T-SQL语法是否符合规定,如果语法不符合要求,就会报错并通过TDS把错误信息传回客户端,最后结束过程。如果语法符合要求,就会生成查询树传入查询优化器中。
命令解释器同时也会检查是否已经存在缓存了的执行计划,如果存在,就重用;如果不存在,就让查询优化器生成执行计划。
4. 查询优化器
该组件是SQL SERVER的核心部分。优化器的作用是对特定的请求进行一系列的优化,使其尽可能高效地对数据进行操作。最终选择最低开销的候选计划生成预估执行计划,并传入查询执行器执行查询。
5. 查询执行器
正如其名,查询执行器是执行查询的组件,但是实际上并不真正执行,而是通过OLE DB协议访问并使用一系列的指令操作存储引擎进行查询的执行操作。存储引擎才是实际的查询执行者。
6. 数据访问方法
数据访问方法是提供数据和索引的存储/查询/修改的代码集合。它包含了所有操作数据的代码,但是并不由它自己去实际操作数据,而是提交请求到缓冲管理器。
7. 缓冲管理器
缓冲(Buffer)管理器是管理Buffer Pool的组件。Buffer Pool是SQL SERVER内存的主要部分,它管理内存中的数据,并把适当的数据作为输出传输给(数据访问方法)。如果所需数据不在内存中,缓冲管理器需要从磁盘读取对应的数据页到内存的数据缓存,然后把所需的数据返回给数据访问方法。这个过程中可能会出现一种等待状态PageIOLatch。
8. 数据缓存
数据缓存(Data Cache)是Buffer Pool中的最大部分,也可以说是SQL SERVER中占用内存最多的部分。它用于存放从磁盘加载到内存中的数据,以便后续操作使用。
(1)查询当前每一个数据库的缓存大小
select count(*) * 8 / 1024 as 'Cached Size (MB)',
CASE database_id
WHEN 32767 THEN 'ResourceDb'
ELSE DB_NAME(database_id)
END AS 'Database'
FROM sys.dm_os_buffer_descriptors
GROUP BY DB_NAME(database_id),database_id
ORDER BY 'Cached Size (MB)' DESC
(2)查询每个库中的脏页数量
缓存中的数据并不是一直存放的,当数据很久没被使用,或者SQL SERVER感觉到有内存压力时,就会释放一部分数据缓存。在该过程中会调用一个叫Lazy Writer的进程,这个进程会把脏页(从磁盘加载到内存后有改动过的数据页)写入磁盘,并释放这部分的空间。如果对实例中每个数据库的脏页数量有兴趣,可以用如下SQL去查:
SELECT DB_NAME(database_id) AS 'Database',
COUNT(page_id) AS 'Dirty Pages(KB)'
FROM sys.dm_os_buffer_descriptors
WHERE is_modified = 1
GROUP BY DB_NAME(database_id)
ORDER BY COUNT(page_id) DESC
TIPS:
如果想知道SQL SERVER保留数据缓存中的数据时间,可以查看性能监视器中的MSSQL$<实例>:Buffer Manager\Page Life Expectancy计数器(PLE)的值。这个值也是判断是否有内存压力的指标之一,微软的建议值是不小于300秒。但是需要说明的是,微软的建议值多存在一定的误导性,比如这里就是一个:300秒是基于4GB内存的32位系统得出来的。对于拥有32GB内存的64位操作系统来说,国外的专家给出的建议是PLE的值不少于2400秒。
9. 事务管理器
事务管理器主要包含两部分:锁管理器和日志管理器。
1)锁管理器通过使用锁机制来保证数据的并发性和隔离性
2)日志管理器通过预写入日志机制,保证事务的ACID特性
TIPS:
当需要修改数据时,数据访问方法会先到事务管理器中通过对事务日志进行操作,把请求传到Buffer管理器中完成,然后返回给数据访问方法并通过事务管理器写入日志文件中。
(三)小结
SQL SERVER是一个复杂的系统,完全了解它的结构几乎不可能,但是每一步出现问题都将对稳定使用和性能带来比较大的影响。