SQL 问题与解答临时表、64 位处理、镜像及其他内容

编辑:Nancy Michell

临时表

问题:我曾听说,为了避免争用问题,最好不要总是使用临时数据库 (tempdb)。事实果真如此吗?我使用临时数据库是因为我需要获得分布在多个表中的数据,甚至随时对它进行修改。借助视图,无法轻易做到这一点。

解答:的确如此,过分使用 tempdb 可能导致发生争用问题。但是,正如知识库文章 (support.microsoft.com/kb/328551) 中所介绍的,争用通常是一种只在较少情况下出现的问题,如当您有数百个 SPID(服务器进程标识符)同时创建和删除大量临时表时。

实际上,使用临时表(可能在也可能不在 tempdb 中)是可接受的一种解决方案。关键在于与构建表的开销相比,您通过从临时表中读取数据所获得的性能提高是否更占上风。

在拒绝该解决方案之前,您需要考虑规模、使用寿命、使用频率,特别是临时表中活动实例的数量。服务器尺寸度量同样非常重要,因为 tempdb 争用可能与硬件有关。

如果您需要在短期内使用大量的小型表,您可以尝试一下表变量,与临时表相比,在这种情况下,表变量更具有优势(请参考下一个问题的解答来了解关于表变量和临时表之间差异的详细介绍,并请参阅“常见问题 — SQL Server 2000 — 表变量”以获得更多信息)。

同样以您为例,如果所有对数据库的查询必须经过临时表创建过程,对原数据模型提出问题而不是仅仅尝试使用它可能也是明智之举。

问题:什么是表变量,它们功能如何?我真的能用它们来代替临时表吗?

解答:临时表与表变量提供了相同的基本功能;事实上,在 tempdb 数据库中,二者都具体化为临时表。然而,如果只插入少量行时,表变量能够表现更为出色。这是因为表变量既不维护统计也不维护索引,因而开销较低。如果表内容不超过数据库引擎要保留在数据缓存中的 8KB 大小的数据库页,在这种情况下,表变量应当是首选。

根据 SQL Server™ Books Online:

  • 表变量的表现类似本地变量。它有良好定义的范围,包括函数、存储过程或在其中声明的批处理。在其范围内,表变量可像普通表一样使用。
  • 在函数、存储过程或表变量被定义的批处理结束时,表变量被自动清除。
  • 与使用临时表相比,存储过程中使用的表变量会导致较少的对存储过程的重新编译。
  • 表变量需要较少的对资源的锁定和记录。
  • 某些情况下,性能可以改进,而状态无法保留。

镜像

问题:我计划使用 SQL Server 2005 镜像以支持更高的可用性。系统将以高可用性模式运行以支持自动故障转移。但是,我仍要运行其他一些镜像中的应用程序以充分利用资源。镜像服务器将支持两类数据库:作为主服务器镜像的 Production 数据库和作为对立数据库的 Staging 数据库。它还支持两类客户端:一种客户端配置了镜像故障转移功能以访问 Production 数据库的客户端,另一类是直接与 Staging DB 相连的客户端。

另外,有些 SQL Server Integration Services (SSIS) 包将在镜像服务器上运行。它们将访问两大数据库,将来自本地服务器中 Staging 数据库的数据传送到主服务器上运行的 Production 数据库。在故障转移过程中,SSIS 包将本地 Staging 数据库的数据传送到本地 Production 数据库(故障转移)。还有我需要了解的与这些配置相关的问题吗?

解答:通常情况下,不建议使用这种配置,因为故障转移后,新的主体数据库可能不堪重负。

功能上,从镜像角度看,似乎不存在问题,但如果您要继续使用本解决方案,应该彻底进行测试。测试应当在最大负荷时和故障转移后以标准配置进行。最大负荷应当是一种估算的未来而非当前的峰值负荷,如果您没有考虑今后的业务需求,一旦负荷超过容量,解决方案将无法工作。

测试可能有效发现网络、磁盘甚至 CPU 的瓶颈,这些瓶颈表现为应用程序响应时间差、吞吐量无法接受、命令超时错误或者镜像服务器中较多的重做队列(这可能会导致依据实际重做率的故障转移时间意想不到的长)。

另外,运行包会断开与出现故障的主体服务器的连接。一旦故障转移完成并且数据库在新的主体服务器中可用,包应该能够与新的主体服务器重新连接。当然,这是依据了这样的假设:包是使用连接重试机制构建的,并且包将正常处理连接错误,如能够从“断开”连接状态恢复。

SQL 服务器和 64 位操作系统

问题:如果我运行 64 位版的 Windows Server® 操作系统,则必须使用 SQL Server 2000 Enterprise Edition(64 位)而不能使用 32 位 SQL Server 2000,对吗?

解答:从 SQL Server 2000 观点看,所支持的唯一纯 64 位体系结构是 Intel 的 ia64。因而,如果 SQL Server 2000 中涉及 64 位支持,指的是 ia64。纯 64 位 ia64 支持的唯一 SQL Server 2000 版本是 Enterprise Edition。既没有像 64 位应用程序一样的运行在 ia64 中的标准版 SQL Server 2000,也没有在 Windows 中的 ia64 Windows®(WOW,可以运行 32 位应用程序的操作系统子系统)系统下运行的标准版 SQL Server 2000。

对于 AMD x64 机器,您有两种针对 SQL Server 2000 的选择,既可以运行 32 位操作系统,在这种情况下,您可以运行任何版本的 SQL Server 2000 和任何服务包 (SP)。也可以在 WOW 中运行 64 位操作系统和 SQL Server 2000(任何版本)SP4。在后一种环境下,SQL Server 2000 并不是纯 64 位应用程序。在 WOW 中,SQL Server 2000 以 32 位模式运行 — 这样,它甚至“感觉不到”这是一个非64 位的环境。

更确切地说,ia64 WOW 和 x64 WOW 是两种完全不同的子系统。在 ia64 中,WOW 必须对受限制的虚拟地址空间进行仿真并进行实际的机器指令仿真。ia64 机器指令仿真与 x86 截然不同 — 它是完全不同的机器。SQL Server 不支持任何其运行在 ia64 WOW 中的组件(SQL Server 2000 或 SQL Server 2005)。

在 x64 WOW 中,情况迥然不同。x86 和 x64 机器的体系结构非常相近。指令集相同(或者基本相同),因此只有 32 位虚拟地址空间必须仿真 — 有针对于此的硬件帮助。因此,有许多支持 x64 WOW 的 SQL Server 组件,如 SQL Server 2000 SP4 和各种版本的 SQL Server 2005。

升级到 SQL Server 2005

问题:我要从 SQL Server 2000 升级到 SQL Server 2005。除了 SQL 代码更新,还要进行哪些应用程序更新?例如,如果我要使用 Microsoft® .NET Framework 客户端连接 SQL Server 2005,则必须将桌面机客户端升级到 Windows XP SP2 吗?

我目前使用 Windows XP SP1 和 Visual Basic® 6.0,以及一些使用 .NET 的应用程序。需要 SQL Server Native Client、.NET Framework 2.0 和 Windows XP SP2 吗?换而言之,升级的整体最小客户端要求是什么?如果我决定采用 SQL Server 2005 镜像,需要变更客户端要求吗?

解答:为了充分利用镜像,您需要使用 SQL Native Client(针对 OLE DB 或 ODBC)或 ADO.NET 2.0 SqlClient。连接字符串应该更改以引用主体服务器及其镜像。

然而,您只需要 SQL Native Client 或 .NET Framework 2.0 来进行客户端镜像感知。以往的客户端能够连接,但不能在主体服务器停机时自动尝试镜像。

您无需接触客户端,即可在客户端与服务器端之间添加 BIG-IP 转换以便通过故障转移手动地将它们从一个箱移至另一个箱。在发生主体服务器连接故障时,您还可以更改应用程序中的代码来尝试与镜像服务器的连接。

系统要求如下:Windows Installer 3.0、Microsoft Windows XP SP1 或更高版本、Microsoft Windows 2000 SP4 或更高版本、以及 Microsoft Windows Server 2003。关于系统要求的详细信息,请参阅“通过 SQL Native Client 使用 ADO”;“将应用程序从 MDAC 更新到 SQL Native Client”以及“SQL Native Client 系统要求

SQL Server 2000 内存不足

问题:当我运行 Windows Server 2003 SP1 中的 SQL Server 2000 Enterprise Edition SP4 产品时,遇到了奇怪的内存不足异常。图 1 显示我从日志中获得的错误信息。

Figure 1 内存不足错误

2006-06-23 14:41:40.72 spid77    WARNING:  Failed to reserve contiguous memory of Size= 24641536.
2006-06-23 14:41:40.85 spid77    Buffer Distribution:  Stolen=4800 Free=1744 Procedures=39391
                                Inram=0 Dirty=90621 Kept=0
                                I/O=0, Latched=99, Other=3063345
2006-06-23 14:41:40.85 spid77    Buffer Counts:  Commited=3200000 Target=3200000 Hashed=3154065
                                InternalReservation=587 ExternalReservation=0 Min Free=1024 Visible= 173320
2006-06-23 14:41:40.85 spid77    Procedure Cache:  TotalProcs=9555 TotalPages=39391 InUsePages=1031
2006-06-23 14:41:40.85 spid77    Dynamic Memory Manager:  Stolen=44191 OS Reserved=7648 
                                OS Committed=7619
                                OS In Use=7603
                                Query Plan=39088 Optimizer=0
                                General=4183
                                Utilities=140 Connection=7651
2006-06-23 14:41:40.85 spid77    Global Memory Objects:  Resource=1617 Locks=313 
                                SQLCache=1836 Replication=204
                                LockBytes=2 ServerGlobal=42
                                Xact=63
2006-06-23 14:41:40.85 spid77    Query Memory Manager:  Grants=0 Waiting=0 Maximum=94533 Available=94533
2006-06-23 14:41:40.88 spid77    Error: 17803, Severity: 20, State: 12
2006-06-23 14:41:40.88 spid77    Insufficient memory available..

我的服务器内存很大 (32GB)。奇怪的是,该问题似乎是随机出现的,导致这一错误的存储过程似乎每 20 次执行就出现一到两次这类异常。

该服务器的性能计数器表明有大量可用内存。惰性写线程 (lazy writer) 没有足够快地向磁盘写入吗?当执行存储过程时,为什么需要如此大量的内存?是选择语句的数量问题还是因为使用了临时表?

解答:这一问题和机器的物理内存数量毫无关系。根据您的 boot.ini 设置方式,应用程序有 2 到 3 GB 的虚拟地址空间。虚拟地址空间是 32 位系统中的宝贵资源。默认方式下,缓冲池将消耗近 384MB 的虚拟地址空间。384MB 被分出来用于线程堆栈和从以下这样一些组件进行分配:这类组件要么太大以至缓冲池无法支持,要么不知道如何从缓冲池分配(第三方扩展存储过程、链接的服务器、COM 组件)。

警告表明近 23MB 的分配失败。这种规模的分配成功与否取决于 384MB 块中其他分配的数量和位置。

您可能会考虑删除一些加载到系统中的第三方扩展存储过程,确定是否存在通过 sp_oacreate 或链接的服务器使用 COM 组件的现象。

当由于在您的存储过程中使用 FOR XML 子句而执行 SQL 存储过程(我们在此没有重复介绍)时,过程可能需要大量内存。然而,如果您想了解更详细的信息,Process\sqlservr\Virtual Bytes 将为您指示仍然有多少虚拟地址空间可用。还有一款称为 VMStat 的工具(包含在随 Jeffrey Richter 撰写的书籍“Programming Applications for Microsoft Windows”附赠的 CD 中),该工具可以确定最大虚拟地址块的大小。此分配中未涉及惰性写线程 (lazy writer);分配要使用的内存区域不在缓冲池中,对吗?

衷心谢谢以下 Microsoft IT 专家,感谢他们与我们分享了技术与专业知识: Ramon Arjona、Stephen Borg、Sandu Chirica、Robert Djabarov、Guillaume Fourrat、Osamu Hirayama、Alejandro Mihanovich、Maxwell Myrick、Uttam Parui、Shashi Ramaka、Gavin Sharpe、Vijay Sirohi、Jimmie Thompson、Madhusudhanan Vadlamaani、Jian Wang 和 Dave Wickert。

© 2008 Microsoft Corporation 与 CMP Media, LLC.保留所有权利;不得对全文或部分内容进行复制.