功到雄奇即罪名,鳜鱼肥,6月26日是什么节日
对于数据库引擎来说,内存是一个性能提升的重要解决手段。把数据缓存起来,可以避免在查询或更新数据时花费多余的时间,而这时间通常是从磁盘获取数据时用来等待磁盘寻址的。把执行计划缓存起来,可以避免重复分析执行计划时带来额外的cpu及各种资源的开销。通过在内存中开辟查询内存空间,可以迅速地完成排序、哈希等计算,达到快速返回运算结果的目的。若没有足够的内存空间,数据库引擎将无法快速地响应用户的请求。
sql server存储引擎本身是一个windows下的进程,所以sql server使用内存和其它windows进程一样,都需要向windows申请内存(通过virtualalloc之类的api向windows申请内存)。
内存芯片提供的物理存储空间,能被cpu直接访问,访问速度快,易丢失。内存性能指标gb/s,ns(纳秒),前者是吞吐量,后者是响应时间。磁盘性能指标mb/s,us(微秒),从两者对比就能看出内存访问速度是远优于磁盘的。
物理内存容量是有限的,如果所有进程都直接使用有限的物理内存,那新的进程将无法为他们找到任何物理内存,那么物理内存将容易成为瓶颈。所以windows会授予每个进程一个虚拟地址空间(virtual address space,vas),通过vas建立应用程序与物理内存的桥梁。
是指一个应用程序能够申请访问的最大地址空间。vas作为中间的抽象层的,不是所有的请求都直接映射到物理内存,它首先映射到vas,然后映射到物理内存。
而两个进程可以共用一个vas,而vas的大小取决于cpu架构,具体请看下面表格:
os type |
kernel model (内核模式) |
user model (用户模式) |
total |
32位系统 |
2gb |
2gb |
4gb |
64位系统 |
8tb |
8tb |
16tb |
vas有两种内存模式,kernel model和user model。kernel model下的vas是供windows系统进程使用,而user model下的vas是供用户进程使用。
由表格可知,32位windows系统应用程序可以访问最大2gb的vas,64windows位系统可以访问最大8tb的vas。这意味着在32位windows系统中一个word文档进程跟一个sql server进程能得到最大2gb的vas是一样的。因此,从理论上讲,这意味着任何应用程序进程在32位windows系统上都将共享最大限度的2 g的vas。
vmm是负责把物理内存在系统中所有需要内存的进程之间作共享,必要时会从vas回收物理内存,把数据存储到页面文件上面去,保证数据永不丢失。当进程需要内存时,vmm会从页面文件中查找数据,并将这数据写入一部分空闲内存当中,然后将新页面映射到需要操作的vas当中。
sql server 2012对内存管理这块跟sql server 2008还是有比较大的区别的,参考一些资料,下面我们来看看两者具体架构。
sql server 2008 r2: sql server 2012:
为了更加清楚了解buffer pool,我们先来了解下 sql server的所需要的内存有哪些,其中包括sql server服务(sqlserver.exe)和其它一些组件所占用的内存,例如sql server代理程序(sqlagent.exe), sql server复制代理程序、sql server报表服务(reportingservicesservice.exe)、sql server analysis services(msmdsrv.exe)、sql server integration services(msdtssrvr.exe),和sql server 全文搜索(msftesql.exe)。
在一台运行sql server的服务器上,运行着sqlserver服务(sqlserver.exe)和其它一些组件。在sqlserver服务(sqlserver.exe)获取到的内存中,又分为2大块:一部分为buffer pool,另一部分为非buffer pool,旧称memtoreserve(默认sqlserver.exe给它预留了256mb)。下表为这两部分内存各自的用途:
sql server 进程所占内存 |
||
buffer pool exec sp_configure n'min server memory exec sp_configure n'max server memory |
非buffer pool(即memtoreserve) (默认为256mb), 可以sqlserver.exe启动时加-g参数,预留足够内存(预留内存大小=256mb+工作线程数*512kb) |
|
buffer pool中主要存放之前查询中的数据页,和索引页。然后根据它自已的算法,自动清理过期过访问或效率低下的页。 |
sql server工作线程 |
占用不多 |
分布式查询引用的ole db访问接口 |
如操作链接服务器 |
|
备份还原 |
维护计划或者t-sql备份恢复 |
|
扩展过程 |
如sp_或sys开头的系统存储过程,sp_oacreate 存储过程 |
|
多页的分配器sql server内存管理器 |
如.net framework程序(它们连接sqlserver的网络包大小为8k, sqlserver默认网络包大小为4k) |
|
.dll文件 |
|
|
sql server clr的microsoft com对象 |
这块内存是<=8kb的存储,适用于sql server 2008及以前,属于buffer pool缓冲池来分配。有存储数据页面,consumer功能组件。
这块内存是>8kb的存储,适用于sql server 2008及以前,不属于buffer pool缓冲池来分配, 有存储consumer功能组件, 第三方代码, threads线程。
这个适用于sql server 2012及以上,整合了single-page,multi-page统称any size page。
它来统一响应sql server 内部各种组件内存申请的请求。因为这个原因,在sql server 2012里面,max server memory 不再像以前的版本那样,只控制buffer pool的大小,也包括那些大于8kb 的内存请求。也就是,max server memory能够更准确地控制sql server 的内存使用了。
从内存架构我们可以看到有page reservation需预先申请的内存,有momory objects从windows api申请的内存,有clr第三方申请的内存。
内存使用分类
(1)database cache(数据页面缓冲区):存放数据页面的缓冲区。sql server数据库里的数据都是以8kb为一个页面存储。当有用户需要使用到这个页面上存储的数据时,sql server会把整个页面都调入内存,供用户使用。所以8kb是数据访问的最小单元。
当用户修改了某个页面上的数据时,sql server会在内存中将这个页面修改,但是不会立刻将这个页面写回磁盘,而是等到后面的checkpoint或lazy write的时候集中处理。
(2)各类consumer
sql server的很多功能组件,都必须要申请内存来完成它们的任务。这些统称为“consumer”。常见有如下:
connection:sql server为每个连接分配一个数据结构,存储关于这个连接的信息。另外,还会分配一个输入缓冲池,缓冲客户端发来的指令;一个输出缓冲池,存放sql server返回的结果,等待客户端取走。
general:一组大杂烩。包括语句的编译、范式化、每个锁数据结构、事务上下文、表格和索引的元数据等。
query plan:语句和存储过程的执行计划。和database cache类似,如果sql server没有内存压力,它就会保留每一个生成的执行计划,供以后的用户重用,减少comlile的消耗。所以query plan也会是一块比较大的内存使用区域。
optimizer:sql server在生成执行计划的过程中需要消耗的内存。
utilities:像bcp、log manager、parallel queries、backup等比较特殊的操作需要的内存。
(3)线程内存
sql server会为每个进程内的每个线程分配0.5mb的内存,以存放线程的数据结构和相关信息。
(4)第三方代码申请的内存(com,xp...)
在sql server的进程里,会运行一些非sql server自身的代码。例如,用户定义的clr或者extended stored procedure代码,linked server需要加载的数据连结驱动,调用sql mail功能需要加载的mapi动态库等。这些代码也会申请内存,会算在sql server自己都不知道。
有些sql server内存的申请方式,是预先reserve一块大的内存,然后在使用的时候一小块一小块地commit。而另外的内存申请则直接从空间里commit。在sql server里,把后一种方式叫stolen。
在sql server里,对database cache,sql server会先reserve,再commit。其他的所有内存使用,基本都是直接commit,都是“stolen”。要重申的是,stolen内存也是正常使用的内存,不是泄漏掉的内存。
之所以要把这两种分开,是因为sql server不会对stolen的内存使用awe功能。也就是说,awe扩展出去的内存,只能用来存放database cache。其他内存还要在原来的那2gb里想办法。
对于sql server自己申请的内存,有两种内存申请单位。
小于等于8kb一个单位内存申请,sql server就分配一个8kb页面。所有这些页面都集中管理,这块内存被称为buffer pool。一次一个页面的这种分配称为single page allocation。
对于大于8kb为单位的内存申请,sql server把它们集中在另外一个区域,称为multi-page allocation(旧称memtoleave)。而这种分配称为multi-page allocation。
类型 |
database cache |
consumer |
3rh party code |
threads |
reserved/commit |
是 |
一般不是 |
一般不是 |
不是 |
stolen |
不是 |
是 |
是 |
是 |
buffer pool (single page) |
所有 |
绝大部分 |
没有 |
没有 |
memtoleave(multi-page) |
没有 |
一小部分 |
所有 |
所有 |
这里的一个例外是运行在sql server进程里的clr代码所申请的内存。这部分内存像第三方代码一样,也是使用memtoleave的内存。但是,clr可能也会用reserve-commit的方式申请内存。所以memtoleave的内存也并不是都是stolen的。
根据sql server内存架构图,我们可以知道,在2012版本上,single page allocation跟multi-page allocation合并为any size page allocation了。而max server memory控制的不但是 buffer pool内存大小,而是所有大于等于小于8kb的内存请求。
如图:
比如我设置最小服务器内存为8g,重新启动下sql server (mssqlserver)服务,再使用dmv来查看当前实例的总内存空间,以及占用内存空间:
--target server memory (kb)最多能申请的内存量
--total server memory (kb)目前使用了多少内存量
select counter_name, ltrim(cntr_value*1.0/1024.0/1024.0)+'g'
as memorygb from sys.dm_os_performance_counters
where counter_name like '%target%server%memory%'or counter_name like '%total%memory%'
从查询结果可以看到当我们在sql server设置最小服务器内存为8g的时候,给sql server分配了多少内存,它就占用多少多少内存,从而达到性能最佳。
这是我初次学习sql server性能调优方面的知识,谢谢博友花阴偷移指点。很多知识点方面可能理解有偏差,希望各个路过大神指点一二。
参考文献:
microsoft.sql.server企业级平台管理实践
sql server 2012 内存管理 (memory management) 改进
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
SQL Server免费版的安装以及使用SQL Server Management Studio(SSMS)连接数据库的图文方法
SQL Server 2017 Developer的下载、安装、配置及SSMS的下载安装配置(图文教程详解)
网友评论