SQL Server 2000开始,如果SQL Server遇到了内存不足的问题,我们会在SQL Server的error log中看到相关的信息和对当前memory分配和使用情况的打印信息.
2009-05-06 16:20:22.38 spid215 BPool::Map: no remappable address found.
2009-05-06 16:20:22.46 spid241 BPool::Map: no remappable address found.
2009-05-06 16:20:22.50 spid8 BPool::Map: no remappable address found.
2009-05-06 16:20:22.52 spid242 Buffer Distribution: Stolen=190614 Free=196 Procedures=271
Inram=0 Dirty=104759 Kept=0
I/O=0, Latched=35, Other=664125
2009-05-06 16:20:22.52 spid242 Buffer Counts: Commited=960000 Target=960000 Hashed=768919
InternalReservation=529 ExternalReservation=1426 Min Free=256 Visible= 191224
2009-05-06 16:20:22.52 spid242 Procedure Cache: TotalProcs=67 TotalPages=271 InUsePages=197
2009-05-06 16:20:22.52 spid242 Dynamic Memory Manager: Stolen=190767 OS Reserved=2584
OS Committed=2542
OS In Use=2538
Query Plan=156155 Optimizer=0
General=15253
Utilities=401 Connection=4046
2009-05-06 16:20:22.52 spid242 Global Memory Objects: Resource=9815 Locks=16467
SQLCache=76 Replication=2
LockBytes=2 ServerGlobal=28
Xact=5011
2009-05-06 16:20:22.52 spid242 Query Memory Manager: Grants=11 Waiting=15 Maximum=1512 Available=0
[@more@]当前这个例子中,遇到问题的SQL Server是32bit的SQL Server 2000.
Commited=960000 Target=960000 这里commited的和target都是960000个page,我们知道SQL Server的memory里面,一个page是8K。所以当前的buffer pool是7500MB。一个32bit的SQL Server 2000使用了7500MB内存,那么肯定是打开了AWE选项。commited表示当前已经使用的内存部分。
对于一个32bit的SQL Server来说,即使我们使用了AWE选项来扩展内存,依然还是有内存限制的。AWE扩展的部分,只能给data cache部分使用。即:用来存放table和index的数据页。
我们知道,一个数据库的内存部分,除了data 的cache之外,还有execution plan,statement,security context,lock ,cursor,optimizer,connection以及一些DLL和provider的内容。那么在32bit的SQL Server下,以上这些部分依然收到2GB内存的限制。
这就是说,即使我们给一个32bit的SQLServer无限制的增加内存,它还是可能遇到memory 不足的情况。
在这里,我们看到Hashed=768919,这个hashed部分指的就是data 和index的cache,这些数据使用hash链表的方式存放的。
接下来我们查看这个部分:
2009-05-06 16:20:22.52 spid242 Dynamic Memory Manager: Stolen=190767 OS Reserved=2584
OS Committed=2542
OS In Use=2538
Query Plan=156155 Optimizer=0
General=15253
Utilities=401 Connection=4046
这个stolen的部分,可以理解为不在AWE扩展中的内存,也就是需要受到2GB限制的内存部分。这里总得stolen的内存在1500MB左右。其中绝大部分被Query Plan消耗了。
Query Plan指的是存放SQL 语句的plan的缓存部分。为什么语句的plan会占用如此多的内存呢?
1.客户有非常多的ad-hoc的语句。导致不能重用已经的plan而要不断的生成新的plan。或者由于某些原因,导致本可以重用plan的语句没有办法重用plan,必须生成新的。
2.这些plan没有办法从内存中清除掉。
通过以下命令可以验证我们的猜测:
Dbcc memorystatus --显示目前SQL server的内存使用和分配状况
Dbcc freeproccache --用来手动清除内存里面的plan cache
Dbcc memorystatus
DBCC ACTIVECURSORS --用来显示当前有多少没有关闭的游标
在这个系统中,我们发现执行完”Dbcc freeproccache“之后SQL plan cache的部分没有减少。这个说明这些plan都是正在使用中的active状态。这种情况下,通常是因为应用程序中有很多没有关闭的游标。
果然,”DBCC ACTIVECURSORS“返回了1万多行。
至此,我们可以得出结论,由于应用程序中的cursor leak,导致很多open的cursor在数据库端,这些open的cursor所引用的sql plan是不能被清除也不能被重用的,这个就是memory问题的原因了。
如果应用程序是使用的JDBC的driver,SQL Server 2000 JDBC SP3 修正了一些由于provider本身导致的cursor leak。但是本文中遇到的问题确是由于应用程序本身没有关闭cursor导致的。所以在处理server side cursor还是要格外小心。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/23623/viewspace-1026719/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/23623/viewspace-1026719/