zoukankan      html  css  js  c++  java
  • 备份数据库的时候设置 BufferCount 选项不正确导致 out of memory 的情况

    备份数据库的时候设置 BufferCount 选项不正确导致 out of memory 的情况

    今天群里面的东辉兄跟我说备份生产数据库的时候报错

    环境:

    32位的SQLSERVER2008

    机器有16G内存

    数据库大小差不多60G

    数据库已经打开了AWE功能

    因为是生产库,暂时不能升级到64位SQL2008,那么还有没有其他办法可以解决这个问题呢??


    上网搜索了一下就找到了这篇文章:

    Incorrect BufferCount data transfer option can lead to OOM condition

    http://blogs.msdn.com/b/sqlserverfaq/archive/2010/05/06/incorrect-buffercount-data-transfer-option-can-lead-to-oom-condition.aspx

    译文:

    今天介绍两个DBA在做数据库备份的时候一般都不会去指定的备份参数。一般备份数据库大家会用下面的方法:

    1、使用SSMS或者TSQL脚本来备份数据库

    2、使用第三方的备份软件,这些第三方软件利用 SQLVDI.DLL暴露出来的编程接口或者使用快照备份

    当你写好备份命令并发送到服务器端的时候,你可以在你的备份命令里添加如下两个参数:

    MAXTRANSFERSIZE 

    BUFFERCOUNT

    联机丛书对于这两个参数的解释是:

    http://technet.microsoft.com/zh-cn/library/ms186865(SQL.105).aspx

    数据传输选项
    BUFFERCOUNT = { buffercount | @buffercount_variable }
    指定用于备份操作的 I/O 缓冲区总数。可以指定任何正整数;但是,较大的缓冲区数可能导致由于 Sqlservr.exe 进程中的虚拟地址空间(VAS)不足而发生“内存不足”错误。
    缓冲区使用的总空间由下面的公式确定:buffercount * maxtransfersize。
    注意
    有关使用 BUFFERCOUNT 选项的重要信息,请参阅不正确的 BufferCount 数据传输选项可以导致 OOM 情况博客


    MAXTRANSFERSIZE = { maxtransfersize | @maxtransfersize_variable }
    指定要在 SQL Server 和备份介质之间使用的最大传输单元(字节)。

    可能的值是 65536 字节 (64 KB) 的倍数,最多可到 4194304 字节 (4 MB)。

    根据你是否提供这两个参数值,SQLSERVER会指定用于备份的连续的缓冲区大小。

    这是对于32位系统中大量的连续的内存分配的 non-Buffer pool区域的虚拟地址空间是至关重要的。这会令备份失败(言下之意,备份使用的是non buffer pool)。

    当使用SQLVDI,重要的是在VDI配置已经完成之后,我们不能改变MAXTRANSFERSIZE 。大量的连续的内存分配决定于备份设备的数量和数据库文件存放的磁盘的数量

    当你进行备份或者还原数据库的时候可以通过跟踪标志3213来查看你的备份/还原 配置参数。

    具体可以参考我这篇文章:《SQLSERVER数据库备份操作和还原操作做了什么

    我会给你们演示指定不正确的BUFFERCOUNT 参数或者不指定这个参数出现的致命错误

    Trace Flag 3213

    我使用下面的SQL命令来备份SQLSERVER数据库

    backup database dbBackup
    
    to disk = 'C:dbBackup1.bak',
    
    disk = 'C:dbBackup2.bak',
    
    disk = 'C:dbBackup3.bak',
    
    disk = 'C:dbBackup4.bak',
    
    disk = 'C:dbBackup5.bak',
    
    disk = 'C:dbBackup6.bak'
    
    with stats = 1, format, buffercount = 10, maxtransfersize = 4194304

    我特意指定了buffercount参数的值为10 和maxtransfersize为4MB

    跟踪标志3213的输出显示了下面的信息

    最后使用了 40MB  buffer 空间去完成备份

    Backup/Restore buffer configuration parameters
    
    Memory limit: 3954MB
    
    Buffer count:               10
    
    Max transfer size:          4096 KB
    
    Min MaxTransfer size:       64 KB
    
    Total buffer space:         40 MB

    上面的内容在SQLSERVER联机丛书上已经提到过。

    我们现在需要知道buffer count不指定的情况下会发生什么。如果我们不指定buffer count,那么buffer count 会比之前指定的时候大

    Backup/Restore buffer configuration parameters
    
    
    Memory limit: 3954MB
    
    
    Buffer count:               26
    
    
    Max transfer size:          4096 KB
    
    
    Min MaxTransfer size:       64 KB
    
    
    Total buffer space:         104 MB

    如果你看到上面的输出会发现不指定的情况下buffer space已经飙升到104MB,这是因为buffer count已经增长到26


    默认的数据库备份的Buffer Count的计算

     

    SQL Server 2005 或以上

    (NumberofBackupDevices * GetSuggestedIoDepth) + NumberofBackupDevices + (2*DatabaseDeviceCount)

    SQL Server 2000

    (NumberofBackupDevices * GetSuggestedIoDepth) + NumberofBackupDevices + (DatabaseDeviceCount)  

    注意:如果使用的是磁盘,那么备份时候GetSuggestedIoDepth的默认值是3

    上面的公式运算完毕之后会返回一个返回值给SQLSERVER,根据备份介质的不同,例如磁盘、tape磁带 、VDI返回不同的值

    根据上面的公式,第一个例子里面我的备份设备是6,磁盘数是1,因此: 在我的例子里buffer count是[(6*3) + 6 + (2*1)]=26

    我将上面的SQL运行在64位SQLSERVER实例上。当我把上面的SQL运行在32位SQLSERVER实例上,

    这将占近三分之一的可用的  non-Buffer  Pool内存 SQL Server(MemToLeave)区域。

    当我使用下面的SQL,从原来的6个备份设备增加到12个,SQLSERVER就会报错

    backup database dbBackup
    to disk = 'C:dbBackup1.bak',
    disk = 'C:dbBackup2.bak',
    disk = 'C:dbBackup3.bak',
    disk = 'C:dbBackup4.bak',
    disk = 'C:dbBackup5.bak',
    disk = 'C:dbBackup6.bak'
    disk = 'C:dbBackup7.bak'
    disk = 'C:dbBackup8.bak'
    disk = 'C:dbBackup9.bak'
    disk = 'C:dbBackup10.bak'
    disk = 'C:dbBackup11.bak'
    disk = 'C:dbBackup12.bak'
    with stats = 1, format, buffercount = 10, maxtransfersize = 4194304

    报错信息

    Msg 3013, Level 16, State 1, Line 1
    BACKUP DATABASE is terminating abnormally.
    Msg 701, Level 17, State 17, Line 1
    There is insufficient system memory to run this query.
    Backup/Restore buffer configuration parameters
    Backup/Restore buffer configuration parameters
    
     
    Memory limit: 4029MB
    
    
    Buffer count:               50
    
    
    Max transfer size:          4096 KB
     
    
    Min MaxTransfer size:       64 KB
    
    
    Total buffer space:         200 MB

    我的32位SQLSERVER 的最大的可用连续块在NON BUFFER POOL (MemToLeave)里面只有157MB,因此, 就会报OOM(out of memory)错误

    大多数第三方备份软件会使用一个 Max Transfer Size值但是不会指定Buffer Count 的大小。如果你在做备份的时候,遇到OOM错误,你应该下意识的检查一下

    Total Buffer Space的使用量在你备份的时候。 

    在这种情况下,你应该减少备份设备的数目或者减少buffer count通过指定buffer count的值在书写备份命令的时候

    下面的表格指出了默认的buffer count值对于不同的备份/还原操作

     

    如果你在数据库完整备份到磁盘的时候想大概估计 Buffer memory的用量,下面的SQL脚本能够计算出来

    DECLARE @MaxTransferSize FLOAT ,
        @BufferCount BIGINT ,
        @DBName VARCHAR(255) ,
        @BackupDevices BIGINT
    
    -- Default value is zero. Value to be provided in MB.
    SET @MaxTransferSize = 0
    
    -- Default value is zero
    SET @BufferCount = 0
    
    -- Provide the name of the database to be backed up
    SET @DBName = 'dbBackup'
    
    -- Number of disk devices that you are writing the backup to
    SET @BackupDevices = 1
    
    DECLARE @DatabaseDeviceCount INT
    
    SELECT  @DatabaseDeviceCount = COUNT(DISTINCT ( SUBSTRING(physical_name, 1,
                                                              CHARINDEX(physical_name,
                                                                  ':') + 1) ))
    FROM    sys.master_files
    WHERE   database_id = DB_ID(@DBName)
            AND type_desc <> 'LOG'
    
     
    
    IF @BufferCount = 0
        SET @BufferCount = ( @BackupDevices * 3 ) + @BackupDevices + ( 2
                                                                  * @DatabaseDeviceCount )
    
    
    IF @MaxTransferSize = 0
        SET @MaxTransferSize = 1
    
    
    SELECT  'Total buffer space (MB): '
            + CAST (( @Buffercount * @MaxTransferSize ) AS VARCHAR(10))

    至于更详细的参数可以参考我这篇文章:《SQLSERVER数据库备份操作和还原操作做了什么


    实验

    我在电脑上安装了一个SQL2005 express版本 32位

    使用下面的SQL语句进行备份就会报OOM错误

    BACKUP DATABASE [test] TO DISK ='E:	est1FULLBACKUP.BAK' ,
    disk = 'E:	est2FULLBACKUP.bak',
    disk = 'E:	est3FULLBACKUP.bak',
    disk = 'E:	est4FULLBACKUP.bak',
    disk = 'E:	est5FULLBACKUP.bak',
    disk = 'E:	est6FULLBACKUP.bak'
    WITH BUFFERCOUNT=999999999,FORMAT
    消息 3013,级别 16,状态 1,第 1BACKUP DATABASE 正在异常终止。
    消息 701,级别 17,状态 123,第 1 行
    没有足够的系统内存来运行此查询。

    但是指定 BUFFERCOUNT=1就不会

    BACKUP DATABASE [test] TO DISK ='E:	est1FULLBACKUP.BAK' 
    WITH BUFFERCOUNT=1

     


    东辉兄的情况

    下午的时候我叫他指定  BUFFERCOUNT=1  试试

    结果没有报OOM错误

    使用了17分钟备份完差不多60G的数据库

    虽然指定  BUFFERCOUNT=1  备份速度会慢一点,但是non buffer pool的内存占用不会那么多

    感谢东辉兄提供这么鲜明的例子o(∩_∩)o  

    如有不对的地方,欢迎大家拍砖o(∩_∩)o 

  • 相关阅读:
    mysql执行顺序及习题
    多表查询
    PyQt5-03-信号与槽
    PyQt5-01-安装及简单例子
    252.anaconda升级版本
    251.anaconda下载资源包慢
    250.anaconda+vscode
    61.基础语法-函数式编程
    60.基础语法-异常的处理
    59.语法基础-包
  • 原文地址:https://www.cnblogs.com/lyhabc/p/3680417.html
Copyright © 2011-2022 走看看