数据库引擎-内存管理

来源:互联网 发布:阿里巴巴 招聘 php杭州 编辑:程序博客网 时间:2024/04/27 11:15

数据库能够高效的读写硬盘上的内容,很大程度是因为它使用了普通应用程序所没有的内存管理机制。为了保证性能,数据库引擎需要将很多信息保存在内存中,典型的例子有:数据文件的位索引表;一个大表的索引页;一个需要经常修改的表;以及数据库本身的一些内部对象,如锁,连接等。本文以SQL Server为例讲述数据库的内存管理。

数据库的内存管理是一个自动的过程,它通常尽可能多的获取内存,直到操作系统出现内存短缺的时候。这个过程不需要管理员的干预,但可以通过参数的设置来影响这一过程。如果数据库在一定时间里不能获取到处理一个查询需要的内存,会出现查询超时的错误,这时候应该提高查询超时的等待时间值,或减少最大并发度,以减少别的查询占用的资源。

那么,每个数据库实例究竟能管理多大的内存呢?
在普通的32位机器上,每个普通进程可以管理2G的内存,可以通过设置系统地启动配置文件,将进程中系统占用空间限制在1G以内,从而使应用程序的用户空间达到3G;
如果服务器上的物理内存超过了4G,可是设置AWE选项,Address Window Extension;通过这个选项,可以扩展Window的寻址方式,使其可以访问最多64G的空间。但是如果系统的物理内存超过16G,系统需要2G的空间来维护页表,因此不能使用之前的3G选项;

在64位服务器上,数据库和普通应用程序一样可以达到虚拟地址的上限,IA64体系结构可以支持7T,X64支持8T。不过不幸的是,操作系统本身并不能支持那么大的物理内存。AWE对64位的机器没有影响。

通过设置选项可以讲数据库的页面锁定在内存中,而不会被操作系统交换出去。这个选项只有在AWE设置的时候才有效。

数据库是如何进行内存管理的呢?
缺省行为是获取尽量多的内存,直到系统的Memory Notification API告知内存短缺。数据库获取的内存主要有两个目的,一个是缓冲区,用于存放数据库高效运行所需的页面,另一个是其他目的,用于附加在数据库进程其他外部组件,如COM等。当数据库启动的时候,他根据一些参数计算缓冲区的虚拟地址空间,预定这些空间,然后只获取少量的内存以使其能够启动。启动后,数据库根据用户连接的数量,用户查询的处理,不断的增加自己的内存。这时有两个参数会影响它,如果超过最大内存限制,那么它会停止申请内存;如果超过最小内存限制,而且系统所需内存增加,它会释放一些页面。数据库可以以几M每秒的速度获取和释放内存,从而很快进行调节。

数据库运行环境是无法预料的,而且数据的重要性是不可估计的。如何才能保证数据页面的内容没有被损毁呢?

它使用两种机制检验一个页面内容的正确性,第一种方法是页面撕裂检查,每隔512个字节,它就在后面写上01或10,两者交替出现。倘若512字节后看到01,再过512字节,又看到01,那么页面的内容必然被破坏了。这是一种比较古老的方式,它的缺点是,别人在写的时候,你不能读取,因为页面的内容已经被修改了,只有重新从硬盘上load出来,才是正确的。在2005引入的新方法是校验和,在页面的头部有页面内容的字节校验和,这样在别人写的时候,也还是可以读的。

 

数据库缓冲区能够支持数据库高效的运转,是因为其在读写方面所做的优化,这样的优化包括提前读和延后写两个方面。

什么是提前读?

每次数据库读取数据页面的时候,会连续读取64个相邻的page,这样可以减少读硬盘的次数,但如果某个页面已经存在于内存中,本次读取会被抛弃。当用户查询需要对一个表进行扫描,那么它会首先找到IAM,然后找到这个表的所有块的起始地址,排序并连接成数组,最后启动若干线程从各个地址开始进行装载。如果对聚集索引进行扫描,它也会先扫描中间节点,根据条件找到符合条件的数据页面的地址,将各个块的地址分离出来,再启动线程分别装载。如果对非聚集索引扫描,它会边扫描索引节点,边发起装载的线程,这样扫描还没有结束,部分节点已经装载进来了。

有时候,几个查询会用到同一个大表的内容。系统会尽量使后面的查询使用前一个装载的页面。这样可以减少io。但是第二个查询开始的页面可能并不是这个表存在硬盘中的第一个页面。所以对于表的查询,如果不用order by是不能保证行的顺序的。

 

什么是延后写?

当数据库对内存中一个页面发生修改后,该页面并不会直接写入到硬盘中,因为它还可能被修改多次,但是每次修改都会被记录在日志中。在这个修改被写入硬盘之前,数据库首先在页面的首尾寻找是否有相邻页面被修改,如果找到了32个连续的页面,或者相邻页面不能被写入硬盘,那么寻找过程就结束了。这时候才真正开始写操作,它通常通过三种方式完成:

懒写,只有当缓冲区不够时,系统将一些不经常访问的页面写入到磁盘中;

迫切写,当进行批量插入的时候,系统不记录相关的日志,页面会并发的写入硬盘;

检查点,这应该是最常用的写方式,检查点进程会定期扫描缓冲区页面,将脏页写入;用户可以申请一个Cehckpoint操作,数据库引擎也会定期产生检查点。

这三种写操作都是异步的,数据库发出请求后并不会等到IO结束再返回进行后面的操作。

 

关于数据库的内存管理还有很多内容,希望以后有机会进一步探讨。

原创粉丝点击