65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SQL-DMO 收缩 SQL Server 事务日志

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.99/5 (43投票s)

2004年4月22日

CPOL

9分钟阅读

viewsIcon

212875

downloadIcon

4737

使用 SQL-DMO 缩减 SQL Server 事务日志。

Sample Image

引言

我们某个部门的员工安装了一个使用 MSDE 作为数据库服务器的应用程序。该应用程序经常无故挂起,直到我们最终发现导致这种奇怪行为的原因是事务日志增长过快。在查阅 MSDN 后,我发现缩减 MSDE/SQL Server 2000 的事务日志只需要 2 个简单的命令(请参阅 KB272318)。

BACKUP LOG %DB_NAME% WITH TRUNCATE_ONLY
DBCC SHRINKFILE (%LOG_NAME%, %LOG_SIZE%)

但是,由于该部门的员工对 MSDE 是什么以及如何使用 osql 工具运行这些命令一无所知,他们请我编写一个简单的向导应用程序来简化他们的工作。我编写的第一个版本使用了 MFC,而第二个版本我使用 WTL 实现,以避免拖入大小为 1 MB 的 mfc dll,并静态链接到 C 运行时。由于需要 C++ 异常支持,我无法最小化 ATL 中的 CRT 使用。

那么这个向导有什么功能呢?

Sample Image

它可以

  1. 缩减 SQL Server 数据库的事务日志。
  2. 缩减数据库后备份数据库。
  3. 创建 SQL Server 作业,该作业会在事务日志达到限制大小时自动缩减它们。
  4. 查看最终结果,即缩减后的事务日志大小。
  5. 将 SQL Server 企业管理器用户界面元素显示为其自身的用户界面元素。

关注点

您可以使用此向导作为执行 SQL-DMO 和 SQL-NS 不同任务的示例。向导的每个页面都将在单独的章节中,并且是以下内容的示例:

登录页面

Sample Image

  1. (SQL-DMO) 列出网络可用的 SQL Server。
  2. (SQL-DMO) 启动已停止的 SQL Server。
  3. (SQL-DMO) 使用 Windows 或 SQL Server 身份验证连接到 SQL Server。
数据库选择页

Sample Image

  1. (SQL-DMO) 列出 SQL Server 数据库,如果需要,排除系统数据库。
  2. (SQL-NS) 显示数据库属性(如果安装了 SQL-NS)。
  3. (SQL-DMO) 列出 SQL Server 数据库的事务日志。
  4. (SQL-DMO) 检索事务日志文件的属性。
备份页

Sample Image

  1. 格式化备份介质集属性(也支持拖放)。
  2. (SQL-DMO) 在备份前验证备份介质集。
缩减页

Sample Image

  1. (SQL-DMO) 启动作业服务器 (SQL Server Agent)。
  2. (SQL-DMO) 创建 SQL Server 作业及其步骤。
  3. (SQL-DMO) 创建触发所创建作业的 SQL Server 警报。
  4. (SQL-DMO) 启动 SQL Server 作业(已注释)。
  5. (SQL-DMO) 缩减事务日志。
  6. (SQL-NS) 使用 SQL Server 企业管理器 UI 备份选定的数据库。
  7. (SQL-DMO) 备份选定的数据库。
  8. (SQL-DMO) 使用事件接收器处理备份对象事件(PercentComplete、Complete 和 NextMedia 事件)。(有关更多详细信息,请参阅 IBackupSink 源代码)。
  9. (SQL-DMO) 备份完成后验证备份介质集文件。
杂项

Sample Image

  1. 执行 SQL Server 服务管理器。
  2. 执行 SQL Server 企业管理器。
  3. 精简 CRT 和全局堆内存。
  4. 显示 COM 错误。
  5. 显示 Win32 错误。

实现

我将不再深入探讨细节,因为源代码本身就很容易理解。只说几句:

此向导使用 Microsoft SQL-DMO (SQL Distributed Management Objects) 和 SQL-NS (SQL Namespace API) 来执行其任务。SQL-DMO 允许用支持 Automation 或 COM 的语言编写的应用程序执行 SQL Server 企业管理器执行的所有功能。

SQL-NS 允许用支持 Automation 或 COM 的语言编写的应用程序将 SQL Server 企业用户界面的部分包含在其自己的用户界面中。

请参阅下图。SQL-NS 建立在 SQL-DMO 之上。

Sample Image

几年前,我编写了一个 Visual Basic 应用程序,该应用程序使用 SQL-DMO 将 Microsoft Access 数据库转换为 SQL Server 数据库(由于循环关系,我们在 SQL 脚本和 SQL Server 导入向导方面遇到了问题)。

我记得,要使用 SQL-DMO 对象,我只需要从 VB 项目中添加对其类型库的引用。但是,从 VC 5.0 开始,我们就有编译器内置的 COM 支持——只需使用 #import 预处理器指令,编译器就会读取类型库并为 COM 接口生成 C++ 包装类和智能指针。因此,我们获得了 VB 的便捷性和 C++ 的强大功能。我之所以提到这一点,是因为绝大多数抱怨是几乎所有的示例都是用 VB 实现的——但将它们转换为 C++ 只是一件小事。此外,使用编译器 COM 支持允许我们在 MFC 和 ATL 中使用相同的代码,甚至不使用任何框架(旧的 MFC 项目也可供下载)。只需查看 示例代码

处理 SQL-DMO 事件会稍微复杂一些。SQL-DMO 的 BackupBulkCopyReplicationRestoreSQLServerTransfer 对象是可连接的 COM 对象,支持回调到客户端应用程序。我们必须实现函数来处理来自服务器的回调,称为接收器。使用 IConnectionPoint 接口,客户端通知服务器其处理回调的能力,并提供其接收器实现作为参数。客户端实现的接收器是 COM 对象。与任何 COM 应用程序开发任务一样,使用 C++ 实现任何 SQL-DMO 可连接对象的接收器都相当容易。客户端应用程序定义一个类,继承自定义的 SQL-DMO 接收器接口定义,然后实现成员来处理感兴趣的回调。IBackupSink缩减页 (CWizPgShrink) 的源代码说明了如何实现一个可以处理备份对象事件的 COM 对象(您还可以使用 _COM_SMARTPTR_TYPEDEF 宏来生成 IConnectionPointContainerIConnectionPoint 智能指针)。

SQL-NS 的使用也通过 #import 指令来导入类型库,并为 SQL-NS 的 COM 接口生成 C++ 包装类和智能指针。请参阅 示例代码

示例代码 (SQL-DMO)

这是一个缩减 "Northwind" 数据库事务日志的示例代码。

//
// g_spSqlServer2 is SQL Server object global pointer
    
static LPCTSTR spszDbs  = _T( "[Northwind]" );
const  LONG    lLogSize = 2;
//
try
{
    SQLDMO::_Backup2Ptr spBackup2 = NULL;
    _CREATEINSTANCE( spBackup2, SQLDMO::Backup2 );

    spBackup2->Database    = (LPCTSTR)spszDbs;
    spBackup2->Initialize  = (VARIANT_BOOL)( TRUE );
    spBackup2->Action      = 
      (SQLDMO::SQLDMO_BACKUP_TYPE)SQLDMO::SQLDMOBackup_Log;
    spBackup2->TruncateLog = 
      (SQLDMO::SQLDMO_BACKUP_LOG_TYPE)SQLDMO::SQLDMOBackup_Log_TruncateOnly;
    
    spBackup2->SQLBackup( g_spSqlServer2 );

    SQLDMO::_Database2Ptr spDatabase2 = 
        g_spSqlServer2->Databases->Item( (LPCTSTR)spszDbs );
    SQLDMO::LogFilesPtr   spLogFiles  = 
        spDatabase2->TransactionLog->LogFiles;
    SQLDMO::_LogFile2Ptr  spLogFile2  = NULL;
        
    LONG lCount = spLogFiles->Count;

    for( LONG l = 1; l <= lCount; l++ )
    {
        spLogFile2 = spLogFiles->Item( l );

        if( spLogFile2->Size > lLogSize )
            spLogFile2->Shrink( lLogSize, 
                SQLDMO::SQLDMOShrink_Default );
    }
}
catch( IN _com_error e )
{
    // Display com error
}
//

示例代码 (SQL-NS)

这是一个像 SQL Server 企业管理器那样显示 "Northwind" 数据库属性的示例代码。

Sample Image

//
// g_spSqlNamespace is ISQLNamespace object global pointer
static LPCTSTR spszDbs = _T( "[Northwind]" );
//
try
{
    LONG lServer    = g_spSqlNamespace->GetRootItem();
    LONG lDatabases = spSqlNamespace->GetFirstChildItem( lServer, 
        SQLNS::SQLNSOBJECTTYPE_DATABASES, (LPCTSTR)NULL );
    LONG lDatabase  = spSqlNamespace->GetFirstChildItem( lDatabases, 
        SQLNS::SQLNSOBJECTTYPE_DATABASE,  (LPCTSTR)spszDbs );

    SQLNS::SQLNamespaceObjectPtr spSQLNSNamespaceObj = 
        g_spSqlNamespace->GetSQLNamespaceObject( lDatabase );
    spSQLNSNamespaceObj->ExecuteCommandByID( SQLNS::SQLNS_CmdID_PROPERTIES, 
        (LONG)(HWND)NULL, SQLNS::SQLNamespace_PreferModeless );
}
catch( IN _com_error e )
{
    // Display com error
}
//

全局函数

  • GetSqlServerPath - 正如您在上面的图片中看到的,如果 SQL Server 服务管理器和 SQL Server 企业管理器在目标机器上可用,程序就可以执行它们。SQL Server 工具文件夹的路径可以从注册表 HKLM\SOFTWARE\Microsoft\Microsoft SQL Server \80\Tools\ClientSetup 键的 SQLPath 值中检索。因此,将 "Binn\sqlmangr.exe" 附加到检索到的值就构成了 SQL Server 服务管理器的完整路径,将 "Binn\SQL Server Enterprise Manager.msc" 附加到检索到的值就构成了 SQL Server 企业管理器的完整路径,我们可以将它们传递给 ::ShellExecute::ShellExecuteEx 函数。

    HKLM\SOFTWARE\Microsoft\MSSQLServer\Setup 注册表键的 SQLPath 值包含 SQL Server 数据根文件夹。GetSqlServerPath 函数为您完成了所有这些工作。

  • DisplayComError - 您认为它做什么?
  • SkipODBCPrefix - SQL-DMO 的 ODBC 错误消息带有前缀,例如 [Microsoft][ODBC SQL Server Driver][SQL Server][SQL DMO]msg... 或类似的内容。尽管将 SQL Server 对象 ODBCPrefix 属性设置为 false 可以移除它们,但有时这些前缀仍然被附加。您可以使用此函数来移除剩余的部分。
  • FormatMessage - 从已加载模块的消息表资源格式化 Win32 API 消息字符串。
  • TrimWorkingSet - 该函数压缩 CRT 和全局堆,并将进程的工作集临时修剪为零,这实际上减少了应用程序对物理 RAM 内存的使用。
  • DoEvents - 来自 Visual Basic 的恐龙。它会将程序执行权交给操作系统处理所有待处理的消息。在密集循环中有用。

已知bug

  1. 我的 CMenuButton见图)不对反射消息做出响应。我必须手动向它发送 BN_CLICK
  2. 如果 CMenuButton 下方没有空间来显示其菜单,它会弹出菜单,但按钮会被菜单遮挡。
  3. 如果您在远程服务器上缩减事务日志,则不支持备份(它会给出路径错误)。我必须尝试使用临时备份设备来查看问题是否仍然存在。
  4. 在备份前验证备份介质集有时会给出错误(尝试添加两个相同的介质集文件和一个新文件)。我非常不喜欢这部分代码。而且更不喜欢之前的实现(它已被注释掉)。如果有人有任何改进此处的想法,我将非常感激。

未知 bug

这是我的第一个 WTL 应用程序。请注意许多未知的和其它类型的 bug :) 欢迎所有改进、优化和修复。

项目依赖项

程序依赖项

  1. Microsoft SQL-DMO 8.0
  2. Microsoft Windows 2000 或更高版本(不支持 Windows 9x)

项目依赖项说明

我已从项目中删除了 rcstamp.exe(用于增加项目构建号的工具),以减小其大小。如果您想自动增加项目构建号,请下载 RCStamp 工具,将其复制到解决方案的 bin 子目录中,并在项目的生成后步骤中添加以下行:

对于 VC 6.0: "$(WkspDir)\bin\RCStamp.exe" "$(WkspDir)\$(TargetName) \$(TargetName).rc" *.*.+.*

对于 VC 7.0 及更高版本: "$(SolutionDir)\bin\RCStamp.exe" "$(ProjectDir)$(TargetName).rc" *.*.+.*

此项目最初是用 VS.NET 2003 开发的,然后手动转换为 VC 6.0,并使用 将 VS.NET 2003 项目文件转换为 VS.NET 2002 的实用工具转换为 VS.NET 2002。原始 VS.NET 2003 解决方案文件命名为 tlsw.sln.2003tlswa.vcproj.2003 - 您可以将其重命名回原来的名称。

程序设置

安装程序 inf 文件也包含在项目中。您可以使用 IExpress 工具构建一个小型的安装程序 exe。IExpress 随 Microsoft Internet Explorer Administration Kit 一起提供——它允许构建小型快速的安装包。我的安装程序 inf 文件将应用程序可执行文件和帮助文件复制到 Windows 系统文件夹(因为这是一个管理工具),在 [开始菜单]>[程序]> [公司名称]>[事务日志缩减向导] 目录中创建指向它们的快捷方式,并注册卸载所需的信息(您可以在控制面板的 [添加/删除程序] 中将其卸载)。注意:不包含 SQL-DMO 和 SQL-NS 的安装脚本。创建安装程序 inf 文件稍微偏离主题,我将在另一篇文章中介绍该主题。

致谢

  1. peterchen 提供的用于增加项目构建号的 RC Stamp 工具。
  2. 感谢 Robert Edward Caldecott 提供了使用 Marlett 字体显示字形的绝妙想法。我在 MSDN(创建向导)中发现了这个技巧,是在下载了他的文章代码(参见向导介绍页的项目符号)之后。
  3. 同一个人 Robert Edward Caldecott 编写的 WTL 自适应属性表
  4. Paul Bludov 编写的 WTL bug
  5. Michael Dunn 编写的文章 MFC 程序员的 WTL
  6. Ed Gadziemski 提供的 十个 WTL 技巧和窍门
  7. dacris 提供的 将 VS.NET 2003 项目文件转换为 VS.NET 2002 的实用工具

历史

  • 2004 年 4 月 19 日 - 发布了文章。
© . All rights reserved.