数据库性能优化概述

性能调节的目的是通过将网络流通、磁盘 I/O 和 CPU 时间减到最小，使每个查询的响应时间最短并最大限度地提高整个数据库服务器的吞吐量。为达到此目的，需要了解应用程序的需求和数据的逻辑和物理结构，并在相互冲突的数据库使用之间（如联机事务处理 (OLTP) 与决策支持）权衡。

对性能问题的考虑应贯穿于开发阶段的全过程，不应只在最后实现系统时才考虑性能问题。许多使性能得到显著提高的性能事宜可通过开始时仔细设计得以实现。为最有效地优化 Microsoft® SQL Server™ 2000 的性能，必须在极为多样化的情形中识别出会使性能提升最多的区域，并对这些区域集中分析。

虽然其它系统级性能问题（如内存、硬件等）也是研究对象，但经验表明从这些方面获得的性能收益通常会增长。通常情况下，SQL Server 自动管理可用的硬件资源，从而减少对大量的系统级手动调节任务的需求（以及从中所得的收益）。

主题 | 描述
设计联合数据库服务器 | 描述如何通过将处理负荷分摊在多个服务器间而达到高性能级别（如大型 Web 站点等所需的性能级别）。
数据库设计 | 描述数据库设计如何成为提高总体性能的最有效途径。数据库设计包括逻辑数据库架构（如表和约束）和物理特性（如磁盘系统、对象位置和索引）。
查询优化 | 描述正确设计的查询（用于应用程序）如何显著提高性能。
应用程序设计 | 描述正确设计的用户应用程序如何显著提高性能。应用程序设计包括事务边界、锁定和批处理的使用。
优化实用工具和工具性能 | 述及 Microsoft SQL Server 2000 提供的实用工具和工具的一些可用选项，描述这些选项如何突出说明提高这些工具的性能的方法，以及同时运行这些工具和应用程序的效果。
优化服务器性能 | 描述如何更改操作系统（Microsoft Windows NT®、Microsoft Windows® 95、Microsoft Windows 98 或 Microsoft Windows 2000）和 SQL Server 的设置以提高总体性能。


设计联合数据库服务器

为达到大型 Web 站点所需的高性能级别，多层系统一般在多个服务器之间平衡每一层的处理负荷。Microsoft® SQL Server™ 2000 通过对 SQL Server 数据进行水平分区，在一组服务器之间分摊数据库处理负荷。这些服务器相互独立，但也可以相互协作以处理来自应用程序的数据库请求；这样的一组协作服务器称为联合体。

只有当应用程序将每个 SQL 语句发送到拥有该语句所需的大部分数据的成员服务器时，联合数据库层才可以达到非常高的性能级别。这称为使用语句所需的数据配置 SQL 语句。使用所需的数据配置 SQL 语句不是联合服务器所独有的要求；在群集系统中同样有此要求。

虽然服务器联合体与单个数据库服务器呈现给应用程序的图像相同，但在实现数据库服务层的方式上存在内部差异。

单个服务器层 | 联合服务器层
生产服务器上有一个 SQL Server 实例。 | 每个成员服务器上都有一个 SQL Server 实例。
生产数据存储在一个数据库中。 | 每个成员服务器都有一个成员数据库。数据分布在成员数据库之间。
一般每个表都是单个实体。 | 原始数据库中的表被水平分区为成员表。一个成员数据库有一个成员表，而且使用分布式分区视图使每个成员服务器上看起来似乎都有原始表的完整复本。
与单个服务器的所有连接和所有 SQL 语句都由 SQL Server 的同一个实例处理。 | 应用程序层必须能够在包含语句所引用的大部分数据的成员服务器上配置 SQL 语句。

虽然目的是设计数据库服务器联合体来处理全部的工作负荷，但是可通过设计一组在不同的服务器之间分布数据的分布式分区视图来达到此目的。

请参见

联合 SQL Server 2000 服务器

创建分区视图


设计分区

如果数据库中的表可自然划分为相似的分区，而且可以将分区中由 SQL 语句访问的大部分行放置在同一成员服务器上，则分区很有效。表被群集在相关的单元中。例如，假设某个订单项引用"订单"表、"客户"表、"部件"表以及所有记录客户、订单和部件之间关系的表。如果可以将逻辑群集中的所有行放置在同一个成员服务器上，则分区最有效。

对称分区

如果可以对数据库中的表进行对称分区，则分区最有效：

  • 由于可以将相关数据放置在同一个成员服务器上，因此大多数路由到正确成员服务器的 SQL 语句对其它成员服务器上的数据需求量将很少（如果需要）。分布式分区视图的设计目的可以确定为 80/20 规则：将分区设计成可将大多数 SQL 语句路由到某个成员服务器，在该服务器上至少有语句所需的 80% 的数据，而只有 20% 或更少的数据需要通过分布式查询获得。测试能否达到设计目的的较好方法是，看分区是否允许将所有的行都放在这些行引用的外键行所在的同一个服务器上。支持此目的的数据库设计适合分区。

  • 在成员服务器之间对数据进行统一分区。

    例如，假设某个公司将北美洲分成了多个区域。每个区域由一个职员负责，客户主要在其居住的州或省购物。按区域对区域表和职员表进行分区。按州或省对不同区域间的客户进行分区。虽然某些查询需要多个区域的数据，但大部分查询所需的数据都在一个区域的服务器上。应用程序将 SQL 语句路由到包含从用户输入的内容推知其所在区域的成员服务器。

非对称分区

虽然对称分区是理想的目标，但多数应用程序所具有的复杂数据访问模式阻碍了对称分区。非对称分区导致某些成员服务器所承担的任务比其它服务器多。例如，可能只能对数据库中的部分表进行分区，没有被分区的表仍保留在原始服务器上。非对称分区可以提供对称分区的很多性能，并具有如下优点：

  • 显著提高某些数据库的性能，这些数据库无法通过非对称分区其中某些表来进行对称分区。

  • 通过一系列反复的非对称改进，成功地对大型现有系统进行分区。每一步中选择的分区表通常是在当时提供最大性能收益的表。

在非对称方法中，原始服务器通常保留一些不适合分区方案的表。这些保留表的性能通常比在原始系统中快，因为成员表移动到成员服务器，从而减小了原始服务器的负荷。

有多种方法可以对许多数据库进行分区。所实现的特定分区必须最好地满足由业务服务层执行的典型范围的 SQL 语句要求。

分布式分区视图

在设计分区时还应制定路由规则，可由应用程序用来确定哪个成员服务器能够最有效的处理每个 SQL 语句。业务服务层必须能够将某个用户数据块与路由规则进行匹配，以找出处理 SQL 语句的成员服务器。

在设计一组分布式分区视图以实现数据库服务器联合体时，需考虑以下四个方面：

  • 确定应用程序执行 SQL 语句的模式。

    制定在典型处理时段由应用程序执行的 SQL 语句的列表。将列表划分为 SELECT、UPDATE、INSERT 和 DELECT 几类，并在每一类中按执行频率排序。如果 SQL 语句引用存储过程，则从存储过程使用基本的 SELECT、INSERT、UPDATE 和 DELETE 语句。如果正在对现有 Microsoft® SQL Server™ 2000 数据库进行分区，可使用 SQL 事件探查器获得这种列表。

    对于使用 SQL 语句的频率，建议以产生使分布式分区视图最有效的典型联机事务处理 (OLTP) 或 Web 站点数据库中的合理近似值为准。这些系统的特点是，与决策支持或 OLAP 系统中的查询类型相比，各 SQL 语句检索的数据量相对较少。当各 SQL 语句引用的数据量较少时，只需研究系统中每个语句所产生的数据流量合理近似值的频率。然而，很多系统都有一些引用大量数据的 SQL 语句组。可能需要采取额外的措施加大这些查询的份量，以反映其对大量数据的要求。

  • 确定表间的关系。

    目的是找到可以在同一维度（如部件编号或部门编号）上进行分区的表群集，这样和该维度的个别事件相关的所有行都在同一个成员服务器上结束。例如，可能决定按区域对数据库进行分区。若要支持此功能，即使是键中没有区域号的表也必须能够以某种与区域相关的方式被分区。在这样的数据库中，即使"客户"表没有区域号列，但如果将区域定义为整个州或省的集合，则 Customer.StateProvince 列可用来以某种与区域相关的方式对客户进行分区。

    因为显式和隐性外键定义了表间的关系，所以在查找分区数据的方法时，它们是考察的主要元素。研究显式外键定义，确定查询通常如何使用一个表中的行来查找另一个表中的行。还要研究隐性外键，或 SQL 语句在联接操作中使用一个表中的行值引用另一个表中行的方式，即使没有明确的外键定义。因为没有将隐性外键显式地定义为数据库架构的一部分，所以必须考察由应用程序生成的 SQL 语句，了解是否有使用非键列联接表的语句。这些隐性外键通常都有索引以提高联接性能，因此还应检查数据库中定义的索引。

  • 使 SQL 语句的使用频率与分析外键时所定义的分区相匹配。

    选择最支持应用程序的混合 SQL 语句的分区方式。如果可以多种方式对某些表集进行分区，则通过 SQL 语句的使用频率确定哪些分区满足的 SQL 语句数目最多。SQL 语句引用最频繁的表就是要最先分区的表。根据引用表的频率排列对表进行分区的优先顺序。

    SQL 语句模式也影响是否对表进行分区的决定：

    • 如果引用表的语句中有 5% 以上是 INSERT、UDATE 或 DELETE 语句，则应对表进行分区，而且可以在选定的维度上对表进行分区。

    • 如果 INSERT、UPDATE 或 DELETE 语句在引用表的语句中不足 5%，则应在每个成员服务器上维护表的完整复本。还需定义更新表的所有复本的方式。如果要求高度的事务完整性，可以对触发器进行编码，使其在分布式事务的上下文中执行所有复本的分布式更新。如果不要求高度的事务完整性，可以使用 SQL Server 复制机制之一将更新从表的一个复本传播到所有其它复本。

    • 如果引用表的语句中有 5% 以上是 INSERT、UDATE 或 DELETE 语句，则不要对表进行分区或复制，并且无法在选定的维度上对表进行分区。
  • 定义 SQL 语句路由规则。路由规则必须能够定义哪个成员服务器可以最有效地处理各 SQL 语句。它们必须建立用户输入的上下文和成员服务器之间的关系，该成员服务器包含完成语句所需的大部分数据。应用程序必须能够获得用户输入的某个数据块，并将它与路由规则进行匹配以确定哪个成员服务器应处理 SQL语句。

请参见

联合 SQL Server 2000 服务器

创建分区视图

设计使用联合数据库服务器的应用程序


设计高度可用的联合数据库服务器

大型 Web 站点或内部联机事务处理 (OLTP) 系统的数据必须高度可靠。数据必须是一年 52 星期、一星期 7 天、一天 24 小时可用。在群集应用程序层中，丢失一个服务器可能会降低系统性能，但不会使整个系统停止运行。群集中剩下的服务器将重新平衡负荷，直到可以将替换服务器插入群集中。

虽然 Microsoft® SQL Server™ 2000 不支持这类负荷平衡群集，但支持 Microsoft 群集服务故障转移群集。故障转移群集支持每个群集有一到四个服务器，具体取决于操作系统。群集在应用程序看来就象是单个虚拟服务器。如果主服务器节点出现故障，另一节点将检测出主服务器节点丢失，并自动开始为所有发送到虚拟服务器的请求提供服务。群集在备用节点下保持运行，直到修复或替换主服务器。故障转移群集有助于提供高度可用性，但不执行任何负荷平衡。

请参见

故障转移群集


备份和还原联合数据库服务器

在使用分布式分区视图生成的联合数据库服务器层中，成员服务器形成一个逻辑单元，因此必须协调各成员数据库的恢复操作以确保它们保持正常同步。

Microsoft® SQL Server™ 2000 不需要在成员服务器间协调备份。每个数据库的备份彼此独立，与其它成员数据库的状态无关。因为备份不必同步，所以不存在处理同步的开销，而且运行任务时没有阻塞。

恢复一组成员数据库最重要的特征与恢复任何其它数据库相同。在生成数据库前，计划并测试恢复过程。必须设置可将所有数据库还原到同一逻辑即时点的过程。SQL Server 包括支持将所有成员数据库恢复到同一即时点的功能。

请参见

备份和还原数据库


数据库设计

数据库的设计包括两个组成部分：逻辑设计和物理设计。逻辑数据库设计包括使用数据库组件（如表和约束）为业务需求和数据建模，而无须考虑如何或在哪里物理存储这些数据。物理数据库设计包括将逻辑设计映射到物理媒体上、利用可用的硬件和软件功能使得尽可能快地对数据进行物理访问和维护，还包括生成索引。

要在设计后更改这些组件很困难，因此在数据库应用程序开发的早期阶段正确设计数据库、使其为业务需求建模并利用硬件和软件功能很重要。


逻辑数据库设计

有效使用 Microsoft® SQL Server™ 2000 是从规范化数据库设计开始的。规范化是删除数据冗余的进程。例如，当转换索引序列访问方法 (ISAM) 风格的应用程序时，规范化常包括将单个文件内的数据分解成关系数据库内的两个或更多的逻辑表。之后，Transact-SQL 查询使用关系联接操作重组这些表数据。通过避免更新多个位置的相同数据，规范化提高应用程序的效率并减少因数据不一致引起错误的可能性。

然而规范化也有权衡问题。如果设计没有完全规范化，主要用于决策支持（与需大量更新的事务处理相对）的数据库则可能没有冗余更新，而且可能对查询更易于理解和更高效。不过，在数据库应用程序内，未规范化的数据是比过度规范化数据更普遍的设计问题。较佳的策略是以规范化设计为出发点，然后出于特定原因有选择地非规范化某些表。

有关更多信息，请参见规范化。

无论哪种数据库设计，都应该利用 SQL Server 的下列功能自动维护数据的完整性：

  • CHECK 约束可确保列值有效。

  • DEFAULT 和 NOT NULL 约束避免因缺少列值而引起的复杂性（并减少隐藏的应用程序错误）。

  • PRIMARY KEY 和 UNIQUE 约束强制行的唯一性（并隐性创建索引来实现此强制）。

  • FOREIGN KEY 约束确保相关表内的行始终有匹配的主记录。

  • IDENTITY 列可以高效生成唯一行标识符。

  • timestamp 列确保在多用户更新间进行的高效并发检查。

  • 用户定义的数据类型确保列定义在数据库内的一致性。

利用上述功能可使数据规则对数据库的所有用户均可见，而不是将这些规则隐藏在应用程序逻辑中。这些服务器强制的规则有助于避免因应用程序本身未完全强制完整性规则而引起的数据错误。使用这些功能还可以确保尽可能高效地强制数据完整性。

请参见

数据完整性


数据库设计考虑事项：数据类型

SQL Server 2000 将任何允许空值的固定长度列视为固定长度。因此，将允许空值的 char 列视为固定长度的 char 列。因此，与 SQL Server 的早期版本相比，在 SQL Server 2000 中相同的数据现在需要更多的磁盘空间进行存储，并可能需要更多的 I/O 和其它处理操作。若要解决此问题，请使用可变长度列，而不要使用固定长度列。例如，使用 varchar 数据类型而不是 char 数据类型。然而，如果一个列内所有值的长度都相同或者值的长度相差不大，使用固定长度列更高效。

text 数据类型

可将长度达 8,000 字节的字符串存储在用 char 或 varchar 数据类型定义的列中。使用 char 或 varchar 数据类型使系统定义的字符串函数（如 SUBSTRING）可以用于长度达 8,000 字节的字符串。

请参见

指定列数据类型


物理数据库设计

I/O 子系统（存储引擎）是任何关系数据库的关键组件。数据库的成功执行通常需要在工程的前期阶段精心设计。关系数据库的存储引擎在此设计中占了很大份量，其中包括确定：

  • 使用哪种类型的磁盘硬件，如 RAID（独立磁盘冗余阵列）设备。有关更多信息，请参见 RAID。

  • 如何将数据放置在磁盘上。有关更多信息，请参见使用文件组放置数据。

  • 在访问数据时使用哪种索引设计提高查询性能。有关更多信息，请参见索引优化建议。

  • 如何适当设置数据库的所有配置参数以使数据库很好地运行。有关更多信息，请参见优化服务器性能。


RAID

RAID（独立磁盘冗余阵列）是由多个磁盘驱动器（一个阵列）组成的磁盘系统，可提供更高的性能、可靠性、存储容量和更低的成本。容错阵列分为从 0 到 5 共 6 个 RAID 等级。每个等级使用不同的算法实现容错。

虽然 RAID 不是 Microsoft® SQL Server™ 2000 的一部分，但它的实现直接影响 SQL Server 的性能。SQL Server 一般使用 RAID 等级 0、1 和 5。

说明 RAID 仅在 Microsoft Windows NT 4.0 和 Microsoft Windows 2000 上可用。

I/O 功能（如条带化和镜像）在固件内被高效处理，因此硬件磁盘阵列可以提高 I/O 性能。反之，基于操作系统的 RAID 使成本较低但要占用较长的处理器周期。当成本是考虑因素之一而且需要冗余和高性能时，带奇偶的 Microsoft Windows® NT® 条带集或 Windows 2000 RAID-5 卷是一个较好的解决方案。

数据条带化 (RAID 0) 是具有最佳性能的 RAID 配置，但是如果一个磁盘发生故障，条带集上的所有数据将不可访问。常用的关系数据库管理系统安装技术是在 RAID 0 驱动器上配置数据库，然后将事务日志放置在镜像驱动器上 (RAID 1)。通过镜像事务日志，可以为数据库获取最佳的磁盘 I/O 性能并维护数据可恢复性（假定执行定期数据库备份）。

如果数据必须能够快速恢复，可考虑镜像事务日志并将数据库放置在 RAID 5 磁盘上。RAID 5 提供阵列上的所有数据冗余，在大多数情况下允许单个磁盘发生故障并被替换，而不会中断系统运行。RAID 5 提供的性能比 RAID 0 或 RAID 1 低，但提供更高的可靠性和更快的恢复能力。


制定驱动器性能策略

通过管理驱动器上数据的位置，既可以提高性能也可以实现容错。在管理用于 Microsoft® SQL Server™ 2000 安装的驱动器存储的环境中，性能部分地是指读写操作的速度，而容错是指系统在其一部分发生故障时不丢失任何数据而继续运行的能力。

可使用下列方法管理磁盘驱动器上的数据位置：

  • 0 级以上基于硬件的 RAID（独立磁盘冗余阵列）可保护数据不在媒体发生故障时丢失，并且可以提高性能。有关更多信息，请参见供应商提供的文档。

  • 基于 Microsoft Windows NT® 和 Microsoft Windows® 2000 的磁盘条带化以及带奇偶的磁盘条带化可提高性能。带奇偶的磁盘条带化还可以保护数据不在媒体发生故障时丢失。

  • 基于 Windows NT 或 Windows 2000 的磁盘镜像和双工都是容错机制，可保护数据不在媒体发生故障时丢失。这些机制还可以提高读取性能。

重要 这些容错方法不能替换适当的备份策略。必须执行定期备份以保护数据库和数据免受灾难性损失的危害。

有关 Windows NT 和 Windows 2000 磁盘条带化、镜像和双工的更多信息，请参见 Windows NT 或 Windows 2000 文档。

请参见

备份和还原数据库


RAID 等级和 SQL Server

Microsoft® SQL Server™ 2000 实现的 RAID（独立磁盘冗余阵列）等级一般是 0、1 和 5。

说明 大于 10 (1 + 0) 的 RAID 等级提供额外的容错或性能增强。这些等级往往是专有系统。有关这些 RAID 系统类型的更多信息，请与硬件供应商联系。

等级 0

由于该等级使用称为条带集的磁盘文件系统，因此也称该等级为磁盘条带化。数据分成块并在阵列内的所有磁盘中按固定顺序展开。RAID 0 通过在多个磁盘内的展开操作提高读/写性能，因此可以独立而同时地执行操作。

RAID 0 与 RAID 5 相似，但 RAID 5 还提供容错能力。

等级 1

由于该等级使用称为镜像集的磁盘文件系统，因此也称该等级为磁盘镜像。磁盘镜像提供选定磁盘的冗余的、完全一样的复本。所有写入主磁盘的数据均写入镜像磁盘。RAID 1 提供容错能力且一般可提高读取性能（但可能会降低写性能）。

等级 2

该等级通过使用在所有磁盘中展开奇偶信息的纠错方法添加冗余。该等级还采用磁盘条带化策略，将文件分成字节并在多个磁盘中展开。相对于镜像 (RAID 1) 策略，该策略只对磁盘的使用和读/写性能提供很小的改进。RAID 2 不如其它 RAID 等级高效，而且不常使用。

等级 3

该等级使用与 RAID 2 相同的条带化方法，但纠错方法只需要一个磁盘存储奇偶数据。磁盘空间的使用因数据磁盘数目的不同而异。RAID 3 提供一些读/写性能改进。

等级 4

比起 RAID 2 或 RAID 3，该等级在大得多的块或段内使用条带化数据。与 RAID 3 相似，纠错方法只需要一个磁盘存储奇偶数据。该等级将用户数据和纠错数据分开。RAID 4 不如其它 RAID 等级高效，而且不常使用。

等级 5

该等级也称为带奇偶的条带化，是在新设计中最常用的策略。与 RAID 4 相似，该等级在阵列内的磁盘中将数据条带化成大块。该等级的不同之处是在所有磁盘中写入奇偶信息。数据冗余由这些奇偶信息提供。数据和奇偶信息排列在磁盘阵列上，以使两者始终在不同的磁盘上。带奇偶的条带化比磁盘镜像 (RAID 1) 提供更好的性能。但是，如果条带成员丢失，读取性能将下降（例如当磁盘发生故障时）。

等级 10 (1+0)

该等级也称为带条带化的镜像。该等级使用条带化磁盘阵列，然后将该阵列镜像到另一组完全相同的条带化磁盘上。例如，可以使用五个磁盘创建一个条带化阵列。然后使用另一组五个条带化磁盘镜像该条带化磁盘阵列。RAID 10 提供磁盘条带化以及磁盘镜像冗余这两份性能收益。RAID 10 在所有 RAID 等级中提供最佳的读/写性能，其代价是使用两倍数目的磁盘。


比较 RAID 等级的不同实现

各种 RAID（独立磁盘冗余阵列）的实现方法各有优缺点。

RAID 实现 | 优点 | 缺点
基于 Microsoft® WindowsNT® 的条带化或 Windows 2000 RAID-5 卷 | 无需额外的硬件成本。 | 使用系统处理资源。
基于硬件的条带化 | 不争用处理器周期。在所有 RAID 实现中具有最佳性能。 | 需要额外的专用硬件成本。

Microsoft SQL Server™ 2000 一般使用的 RAID 解决方案提供各种不同等级的冗余和容错。

RAID 实现 | 优点 | 缺点
基于硬件的 RAID 3、5 或 10 | 卓越性能。不争用处理器周期。 | 高成本。
基于硬件的 RAID 1 | 卓越的冗余性能。不争用处理器周期。 | 由于占用更多硬件，需要额外成本。
基于硬件的 RAID 10 | 卓越性能。卓越的冗余性能。 | 由于占用更多硬件，需要额外成本。
基于 Windows NT 的 RAID 1 或 Windows 2000 镜像卷 | 较好冗余性能。低成本。 | 使用系统处理资源。
基于 Windows NT– 或 Windows 2000 的 RAID 5 | 卓越的读取性能。低成本。 | 使用系统处理资源。


关于基于硬件的解决方案

RAID（独立磁盘冗余阵列）等级 0、1、3 和 5 是一般在基于硬件的解决方案中实现的等级。

基于硬件的 RAID 使用智能驱动器控制器和冗余磁盘驱动器阵列，可保护数据不在媒体发生故障时丢失，并且可以提高读/写操作的性能。对于运行 Microsoft® SQL Server™ 2000 的计算机，磁盘阵列是有效的磁盘存储解决方案。

基于硬件的 RAID 等级 1 到 5 自动实现硬件级的冗余和容错。所有等级（0 到 5）在系统处理器上都没有开销。各数据文件一般在一个以上的磁盘中展开。可以实现基于硬件的 RAID 解决方案，为系统提供从媒体故障中无间隔、不间断地恢复的能力。

通常情况下，基于硬件的 RAID 所提供的性能优于 Microsoft Windows NT® 或基于 Windows® 2000 软件的 RAID。例如，通过基于不使用系统软件资源的硬件实现 RAID 5，可以显著提高数据吞吐量。完成这一点需要使用比常规存储解决方案更多的给定容量的磁盘。使用多个控制器可以进一步提高读/写性能和总存储大小。

基于硬件的 RAID 通常提供较好的性能，具体取决于配置情况。它还使管理多个磁盘更容易，允许您将磁盘阵列视为一个磁盘。甚至能够在不关闭系统的情况下替换发生故障的驱动器。基于硬件的解决方案的缺点是成本高，而且可能将您限制在单一的供应商那里。

有关实现基于硬件的 RAID 的更多信息，请与硬件供应商联系。


关于基于 Windows NT&#150; 和 Windows 2000 的磁盘条带化和带奇偶的磁盘条带化

 优化数据库性能

关于基于 Windows NT– 和 Windows 2000 的磁盘条带化和带奇偶的磁盘条带化

通过使用与操作系统兼容的任何硬件，基于 Microsoft® Windows NT 的磁盘条带化和带奇偶的条带化以及 Windows® 2000 RAID-5 卷在软件内实现 RAID 功能。这些基于软件的解决方案是随操作系统一起提供的，因此具有成本优势。

  • 磁盘条带化在卷（从可用空间区域创建）中的条带内写数据。有关卷的更多信息，请参见 Windows NT 或 Windows 2000 文档。

    这些区域大小都相同，并在一个磁盘阵列（最多 32 个磁盘）上展开。条带化在所有磁盘中写数据，因此数据按相同的比率添加到这组磁盘内的所有分区上。

    基于 Windows NT 的磁盘条带化和 Windows 2000 卷集实现 RAID 0。磁盘条带化在所有 Windows NT Server 磁盘管理策略中提供最佳性能，但不提供任何容错保护。

  • 带奇偶的磁盘条带化与磁盘条带化相似。带奇偶的磁盘条带化将奇偶信息条带添加到卷内的每个磁盘分区上。这样可提供与磁盘镜像相当的容错保护，而存放冗余数据所需的空间要少得多。基于 Windows NT 的带奇偶的磁盘条带化和 Windows 2000 RAID-5 卷实现 RAID 5。

当带奇偶的条带集或 RAID-5 卷的某个成员发生严重（例如断电或磁头完全损坏）故障，可以根据其余成员重新生成这个条带集成员的数据。

在大多数活动都包含读数据的计算环境中，带奇偶的条带集和 RAID-5 卷对于数据冗余是较好的解决方案。带奇偶的磁盘条带集和 RAID-5 卷还提高写性能，但不如单独的条带化效果好。创建带奇偶的磁盘条带集或 RAID-5 卷至少需要服务器上的三个物理磁盘。

磁盘条带化在 Windows NT Server、Windows NT 工作站和 Windows 2000 上可用。然而只有 Windows NT Server 和 Windows 2000 支持带奇偶的磁盘条带化。在双引导计算机上，运行 Microsoft MS-DOS® 操作系统时无法访问条带集（包含带奇偶的条带集）。

对于需要冗余且面向读的应用程序，建议在镜像上使用带奇偶的磁盘条带化或 Windows 2000 RAID-5 卷，但带奇偶的磁盘条带化和 RAID-5 卷需要更多的系统内存。

磁盘条带化和带奇偶的磁盘条带化由 Windows NT Disk Administrator 应用程序设置和管理，该程序可从"管理工具"程序组启动。使用可从计算机管理程序启动的 Windows 2000 磁盘管理应用程序设置并管理 RAID-5 卷。

有关设置磁盘条带化或带奇偶的磁盘条带化的更多信息，请参见 Windows NT Server 或 Windows 2000 文档。


关于基于 Windows NT 和 Windows 2000 的磁盘镜像和双工

基于 Microsoft® Windows NT® 和 Windows® 2000 的磁盘镜像和双工通过任何与操作系统兼容的硬件，在软件内实现 RAID（独立磁盘冗余阵列）功能。这些基于软件的解决方案是随操作系统一起提供的，因此具有成本优势。

  • 磁盘镜像通过维护另外一个磁盘上分区的完全冗余复本，保护不受媒体故障的危害。这在恢复丢失的数据和从备份存储设备还原数据时提供保护，避免所涉及的停机时间和消耗。在某种意义上，镜像是连续备份。当从有大量 I/O 负荷的磁盘读数据时，镜像还提供一些性能收益。基于 Windows NT 的磁盘镜像和 Windows 2000 镜像卷实现 RAID 1。

  • 磁盘双工是镜像的一种形式，通过在镜像磁盘上使用不同的磁盘控制器，保护不受控制器故障的危害（不仅保护不受媒体故障的危害）。

磁盘镜像和双工是 Windows NT Server 的功能。二者不受 Windows NT Workstation 的支持。镜像卷是 Windows 2000 的一个功能，在双引导计算机上，当运行 Microsoft MS-DOS® 操作系统时无法访问镜像和双工。

与基于 Windows NT 的带奇偶的磁盘条带化和 Windows 2000 RAID-5 卷相比，基于 Windows NT 的磁盘镜像或双工和 Windows 2000 镜像卷提供更好的写入性能。而且，需要的系统内存更少且在故障期间没有性能下降的迹象。

基于 Windows NT 和 Windows 2000 的磁盘镜像或双工只需要两个或更多的磁盘，因此入口成本较低（与需要三个或更多磁盘的带奇偶的磁盘条带化和 RAID-5 卷相比）。然而，镜像提供的可利用磁盘空间较少（与带奇偶的磁盘条带化或 RAID-5 卷相比），因此每兆字节的成本更高。

磁盘镜像和双工由 Windows NT Disk Administrator 应用程序实现，该程序可从"管理工具"程序组启动。使用可从计算机管理程序启动的 Windows 2000 磁盘管理应用程序设置并管理镜像卷。

有关设置磁盘镜像或双工的更多信息，请参见 Windows NT Server 文档。

说明 Windows NT Server 文档中经常使用术语"镜像"描述磁盘镜像和双工。


分区

将数据库分区可提高其性能并易于维护。通过将一个大表拆分成更小的单个表，只访问一小部分数据的查询可以执行得更快，因为需要扫描的数据较少。而且可以更快地执行维护任务（如重建索引或备份表）。

实现分区操作时可以不拆分表，而将表物理地放置在个别的磁盘驱动器上。例如，将表放在某个物理驱动器上并将相关的表放在与之分离的驱动器上可提高查询性能，因为当执行涉及表之间联接的查询时，多个磁头同时读取数据。可以使用 Microsoft® SQL Server™ 2000 文件组指定将表放置在哪些磁盘上。

硬件分区

硬件分区将数据库设计为利用可用的硬件构架。硬件分区的示例包括：

  • 允许多线程执行的多处理器，使得可以同时执行许多查询。换句话说，在多处理器上可以同时执行查询的各个组件，因此使单个查询的速度更快。例如，查询内引用的每个表可同时由不同的线程扫描。

  • RAID（独立磁盘冗余阵列）设备允许数据在多个磁盘驱动器中条带化，使更多的读/写磁头同时读取数据，因此可以更快地访问数据。在多个驱动器中条带化的表一般比存储在一个驱动器上的相同的表扫描速度要快。换句话说，将表与相关的表分开存储在不同的驱动器上可以显著提高联接那些表的查询的性能。
水平分区

水平分区将一个表分段为多个表，每个表包含相同数目的列和较少的行。例如，可以将一个包含十亿行的表水平分区成 12 个表，每个小表代表特定年份内一个月的数据。任何需要特定月份数据的查询只引用相应月份的表。

具体如何将表进行水平分区取决于如何分析数据。将表进行分区是为了使查询引用尽可能少的表。否则，查询时须使用过多的 UNION 查询来逻辑合并表，而这会削弱查询性能。有关查询水平分区的表的更多信息，请参见视图使用方案。

常用的方法是根据时期/使用对数据进行水平分区。例如，一个表可能包含最近五年的数据，但是只定期访问本年度的数据。在这种情况下，可考虑将数据分区成五个表，每个表只包含一年的数据。

垂直分区

垂直分区将一个表分段为多个表，每个表包含较少的列。垂直分区的两种类型是规范化和行拆分。

规范化是个标准数据库进程，该进程从表中删除冗余列并将其放到次表中，次表按主键与外键的关系链接到主表。

行拆分将原始表垂直分成多个只包含较少列的表。拆分的表内的每个逻辑行与其它表内的相同逻辑行匹配。例如，联接每个拆分的表内的第十行将重新创建原始行。

与水平分区一样，垂直分区使查询得以扫描较少的数据，因此提高查询性能。例如有一个包含七列的表，通常只引用该表的前四列，那么将该表的后三列拆分到一个单独的表中可获得性能收益。

应谨慎考虑垂直分区操作，因为分析多个分区内的数据需要有联接表的查询，而如果分区非常大将可能影响性能。

请参见

使用分区视图


使用文件组放置数据

Microsoft® SQL Server™ 使您得以在数据库内的特定文件组上创建表或索引，而不用在数据库内的所有文件组上创建。通过在特定的磁盘或 RAID（独立磁盘冗余阵列）设备上创建文件组，可以控制将数据库内的表和索引物理定位在什么位置。在特定磁盘上放置表和索引是为了：

  • 提高查询性能。

  • 并行查询。

请参见

文件和文件组


在文件组上放置表

可在特定的文件组上而不是默认文件组上创建表。如果文件组由在不同物理磁盘中展开的多个文件组成，而且每个磁盘都有自己的磁盘控制器，则对表中数据的查询将在这些磁盘中展开，从而提高查询性能。通过在 RAID（独立磁盘冗余阵列）等级 0、1 或 5 设备上创建单个文件可以达到同样的效果。

如果计算机具有多个处理器，Microsoft® SQL Server™ 2000 可以对数据执行并行扫描。如果表的文件组包含多个文件，可对单个表执行多个并行扫描。每当对表进行有序访问时，都创建单独的线程以并行读取每个文件。例如，对在由四个文件组成的文件组上创建的表进行完全扫描时，将使用四个单独的线程并行读取数据。由于使用单独的线程并行扫描每个文件，因此在每个文件组中创建更多的文件有助于提高性能。同样，当查询联接位于不同文件组上的表时，可以并行读取每个表以提高查询性能。

另外，可以在不包含基表的文件组上创建表内 text、ntext 或 image 列。

如果文件太多因而有太多的并行线程，导致磁盘 I/O 子系统内出现瓶颈堵塞，则会最终出现一个饱和点。可以使用 Windows NT® 性能监视器监视 PhysicalDisk 对象和 Disk Queue Length 计数器来识别这些瓶颈堵塞。如果 Disk Queue Length 计数器大于三，应考虑减少文件数。有关更多信息，请参见监视磁盘活动。

尽量将数据在尽可能多的物理驱动器上展开，有利于提高使用多个文件进行并行数据访问时的吞吐量。若要将数据在所有磁盘中均匀展开，请先设置基于硬件的磁盘条带化，再使用文件组将数据在多个硬件条带集中展开（如需要）。

在特定的文件组上创建新表

Transact-SQL

企业管理器

SQL-DMO

在其它文件组上放置现有的表

企业管理器

企业管理器

请参见

文件和文件组

在文件组上放置索引

使用文件备份


在文件组上放置索引

默认情况下，索引创建在基表所在的文件组上，该索引即在该基表上创建。不过，可以在不同于包含基表的文件组的其它文件组上创建非聚集索引。通过在其它文件组上创建索引，可以在文件组通过自带的控制器使用不同的物理驱动器时实现性能提升。这样一来，数据和索引信息即可由多个磁头并行读取。例如，如果文件组 f1 上的 Table_A 和文件组 f2 上的 Index_A 都由同一个查询使用，就可无争夺地充分利用这两个文件组，因此可以实现性能提升。但是，如果 Table_A 由查询扫描而没有引用 Index_A，则只利用文件组 f1，因而未实现性能提升。

然而，由于不能预测将要发生的访问类型以及访问时间，因此更安全的决策可能是将表和索引在所有文件组中展开。这将保证能够访问所有磁盘，因为所有数据和索引在所有磁盘上均匀展开，不受访问数据的方式的限制。这对系统管理员来说也是更简单的方法。

如果表上有聚集索引，数据和该聚集索引将始终驻留在相同的文件组内。因此，可以在基表上创建一个聚集索引，指定另外一个文件组，在该文件组上新建索引（然后可以除去该索引，而只在新文件组内保留基表），从而将表从一个文件组移动到另一个文件组。

如果表的索引跨越多个文件组，则必须将所有包含该表及其索引的文件组一起备份，之后还必须创建事务日志备份。否则，只能备份索引的一部分，导致还原备份时无法恢复索引。有关更多信息，请参见使用文件备份。

说明 单个表或索引只能属于一个文件组，而不能跨越多个文件组。

在特定的文件组上创建新索引

Transact-SQL

企业管理器

SQL-DMO

在其它文件组上放置现有的索引

企业管理器

企业管理器

请参见

文件和文件组


索引优化建议

可以在不影响数据库架构和应用程序设计的情况下除去、添加和更改索引。高效的索引设计对获得好的性能极为重要。正因为如此，应该尽量试验不同的索引。索引优化向导可分析查询并建议应该创建的索引。有关更多信息，请参见索引优化向导。

Microsoft® SQL Server® 2000 查询优化器在多数情况下可靠地选择最高效的索引。总体索引设计策略应为查询优化器提供更多的索引选择机会，并支持其做出正确的决定。这在各种情形下可减少分析时间并取得较好的性能。

不要总是将使用索引等同于好的性能，反之亦然。如果使用索引总能产生最佳性能，查询优化器的工作就太简单了。实际上，不正确的索引检索选择会导致比最佳性能差的结果。因此，查询优化器的任务是只在索引检索能提高性能时才选择使用索引检索，在其妨害性能时则避免使用。

关于创建索引的建议如下：

  • 将更新尽可能多的行的查询写入单个语句内，而不要使用多个查询更新相同的行。仅使用一个语句，就可以利用优化的索引维护。

  • 使用索引优化向导分析查询并获得索引建议。有关更多信息，请参见索引优化向导。

  • 对聚集索引使用整型键。另外，在唯一列、非空列或 IDENTITY 列上创建聚集索引可以获得性能收益。有关更多信息，请参见使用聚集索引。

  • 在查询经常用到的所有列上创建非聚集索引。这可以最大程度地利用隐蔽查询。有关更多信息，请参见使用非聚集索引。

  • 物理创建索引所需的时间在很大程度上取决于磁盘子系统。需要考虑的重要因素包括：
    • 用于存储数据库和事务日志文件的 RAID（独立磁盘冗余阵列）等级。

    • 磁盘阵列中的磁盘数（如果使用了 RAID）。

    • 每个数据行的大小和每页的行数。这将决定为创建索引须从磁盘读取的数据页的数目。

    • 索引中的列数和使用的数据类型。这将决定必须写入磁盘的索引页的数目。
  • 检查列的唯一性。有关更多信息，请参见使用唯一索引。

  • 在索引列中检查数据分布。通常情况下，为包含很少唯一值的列创建索引或在这样的列上执行联接将导致长时间运行的查询。这是数据和查询自身的基本问题，通常不识别这种情况就无法解决这类问题。例如，如果物理电话簿按姓的字母顺序排序，而城市里所有人的姓都是 Smith 或 Jones，则无法快速找到某个人。

请参见

统计信息


优化事务日志性能

对创建事务日志文件的一般建议包括：

  • 将事务日志创建在物理上单独的磁盘或 RAID（独立磁盘冗余阵列）设备上。将事务日志文件按序列写入，因此使用单独的专用磁盘可使磁头保持在下一个写入操作的位置。

  • 将事务日志文件的初始大小设置为合理大小，以防止当需要更多的事务日志空间时文件自动扩展。当事务日志扩展时，将创建一个新的虚拟日志文件，并且写入事务日志的操作在事务日志扩展时会等待。如果事务日志扩展得过于频繁，性能可能会受不良影响。

  • 将文件增长增量百分比设置为合理的大小，以防止文件按太小的值增长。如果文件增长幅度与写入事务日志的日志记录数相比太小，则事务日志可能需要始终扩展，因而将妨害性能。

  • 手工收缩事务日志文件，而不是允许 Microsoft® SQL Server™ 2000 自动收缩文件。在正忙的系统上，收缩事务日志可能会因数据页的移动和锁定而妨害性能。

请参见

事务日志

虚拟日志文件


优化 tempdb 性能

对 tempdb 数据库的物理位置和数据库选项设置的一般建议包括：

  • 使 tempdb 数据库得以按需自动扩展。这确保在执行完成前不终止查询，该查询所生成的存储在 tempdb 数据库内的中间结果集比预期大得多。

  • 将 tempdb 数据库文件的初始大小设置为合理的大小，以避免当需要更多空间时文件自动扩展。如果 tempdb 数据库扩展得过于频繁，性能会受不良影响。

  • 将文件增长增量百分比设置为合理的大小，以避免 tempdb 数据库文件按太小的值增长。如果文件增长幅度与写入 tempdb 数据库的数据量相比太小，则 tempdb 数据库可能需要始终扩展，因而将妨害性能。

  • 将 tempdb 数据库放在快速 I/O 子系统上以确保好的性能。在多个磁盘上条带化 tempdb 数据库以获得更好的性能。使用文件组将 tempdb 数据库放在除用户数据库所使用的磁盘之外的磁盘上。

请参见

扩充数据库


文件系统

服务器性能不受所使用的文件系统（FAT 或 NTFS）影响。对文件系统的选择应由下列非性能的因素决定。

  • 在运行 Microsoft® MS-DOS®、Microsoft Windows® 95 或 Microsoft Windows 98 的计算机上，文件分配表 (FAT) 文件系统允许双引导。

  • Microsoft Windows NT® 文件系统 (NTFS) 具有安全和恢复的优点。

    如果不需要用 MS-DOS 或 Windows 95/98 双引导 Windows NT 或 Windows 2000，建议使用 NTFS。

警告 一定不能将 Microsoft SQL Server™ 2000 数据和事务日志文件放在压缩文件系统上。

有关选择适当文件系统的更多信息，请参见操作系统文档。

说明 在 Windows NT 上运行时，如果将数据库创建在使用 NTFS 格式化的磁盘上，具体地说是 64 KB 扩展盘区大小的磁盘上，则可以进一步提高 SQL Server 性能。有关格式化 NTFS 磁盘的更多信息，请参见 Windows NT 文档。


查询优化

完全通过系统级服务器性能优化（如内存大小、文件系统类型、处理器的数目及类型等）解决性能问题可能很诱人。但经验表明大多数性能问题不能用这种方法解决。必须通过这些方法解决性能问题：分析应用程序以及应用程序提交给数据库的查询和更新，并分析这些查询和更新如何与数据库架构交互。

持续时间意外地长的查询和更新可能由下列原因引起：

  • 网络通讯速度慢。

  • 服务器计算机的内存不足或 Microsoft® SQL Server™ 2000 可用的内存不足。

  • 缺少有用的统计数据。

  • 统计数据过期。

  • 缺少有用的索引。

  • 缺少有用的数据条带化。

当查询或更新花费的时间比预期的长时，使用下面的检查清单提高性能。

说明 建议在与技术支持提供商联系之前先参考该检查清单。

  1. 性能问题与查询以外的组件是否有关？例如，问题是否为网络性能慢？是否有任何其它可能引起或间接导致性能下降的组件？可以使用 Windows NT 性能监视器监视与 SQL Server 相关和与 SQL Server 不相关的组件性能。有关更多信息，请参见使用系统监视器进行监视。

  2. 如果性能问题与查询相关，涉及哪个查询或哪组查询？使用 SQL 事件探查器帮助识别慢速查询。有关更多信息，请参见使用 SQL 事件探查器进行监视。

    通过使用 SET 语句启用 SHOWPLAN、STATISTICS IO、STATISTICS TIME 和 STATISTICS PROFILE 选项，可以确定数据库查询性能。

    • SHOWPLAN 描述 SQL Server 查询优化器选择的数据检索方法。有关更多信息，请参见 SET SHOWPLAN_ALL。

    • STATISTICS IO 报告与语句内引用的每个表的扫描数、逻辑读取数（在高速缓存中访问的页数）和物理读取数（访问磁盘的次数）有关的信息。有关更多信息，请参见 SET STATISTICS IO。

    • STATISTICS TIME 显示分析、编译和执行查询所需的时间（以毫秒为单位）。有关更多信息，请参见 SET STATISTICS TIME。

    • STATISTICS PROFILE 显示每个查询执行后的结果集，代表查询执行的配置文件。有关更多信息，请参见 SET STATISTICS PROFILE。

    在 SQL 查询分析器中，还可以打开 graphical execution plan 选项查看关于 SQL Server 如何检索数据的图形表示。

    由这些工具收集的信息使您得以确定 SQL Server 查询优化器正在如何执行查询以及正在使用哪些索引。利用这些信息，可以确定通过重写查询、更改表上的索引或修改数据库设计等方法能否提高性能。有关更多信息，请参见分析查询。

  3. 是否已经用有用的统计数据优化查询？

    SQL Server 自动在索引列上创建对列内的值分布情况的统计。也可以使用 SQL 查询分析器或 CREATE STATISTICS 语句在非索引列上手动创建统计；或者如果将 auto create statistics 数据库选项设置为 true，则自动在非索引列上创建统计。查询处理器可以利用这些统计确定最佳的查询评估策略。在联接操作所涉及的非索引列上维护附加的统计信息可以提高查询性能。有关更多信息，请参见统计信息。

    使用 SQL 事件探查器或 SQL 查询分析器内的图形执行计划来监视查询，以确定查询是否有足够的统计信息。有关更多信息，请参见错误和警告事件分类。

  4. 查询统计信息是否为最新？统计信息是否自动更新？

    SQL Server 自动在索引列上创建并更新查询统计（只要没有禁用自动查询统计更新特性）。另外，可以使用 SQL 查询分析器或 UPDATE STATISTICS 语句在非索引列上手工更新统计；或者如果 auto update statistics 数据库选项设置为 true，则自动在非索引列上更新统计。最新的统计不取决于日期或时间数据。如果尚未进行 UPDATE 操作，则查询统计信息仍是最新的。

    如果没有将统计设置为自动更新，则应设置为自动更新。有关更多信息，请参见统计信息。

  5. 是否有合适的索引？添加一个或多个索引是否会提高查询性能？有关更多信息，请参见索引优化建议。

  6. 是否有任何数据热点或索引热点？如果有，考虑使用磁盘条带化。有关更多信息，请参见使用文件组放置数据和 RAID。

  7. 是否为查询优化器提供了优化复杂查询的最有利条件？有关更多信息，请参见查询优化建议。

请参见

高级查询概念

查询处理器构架

用 SQL Server 企业管理器进行监视

SET

并行查询处理


分析查询

Microsoft® SQL Server™ 2000 提供三种方法显示有关自己在查询中如何浏览表以及如何使用索引访问数据的信息：

  • 使用 SQL 查询分析器以图形方式显示执行计划

    在 SQL 查询分析器中单击"查询"菜单并选择"显示执行计划"选项。执行查询后，可以选择"执行计划"选项卡查看执行计划输出的图形表示。有关更多信息，请参见使用 SQL 查询分析器以图形方式显示执行计划。

  • SET SHOWPLAN_TEXT ON

    执行该语句后，SQL Server 返回每个查询的执行计划信息。有关更多信息，请参见 SET SHOWPLAN_TEXT。

  • SET SHOWPLAN_ALL ON

    该语句与 SET SHOWPLAN_TEXT 相似，但输出格式简洁。有关更多信息，请参见 SET SHOWPLAN_ALL。

当显示执行计划时，并不执行提交给服务器的语句；相反，SQL Server 分析查询并显示语句如何作为一系列运算符执行。

说明 由于显示执行计划时不执行语句，因此创建表之类的 Transact-SQL 操作并不实际创建表。因此，后面涉及表的操作将由于表不存在而返回错误。

将显示查询引擎使用的个别数据操作语言 (DML) 和 Transact-SQL 语句的最佳执行计划，并显示如下编译时信息：存储过程、由批处理唤醒调用的触发器、调用的存储过程及任意数目调用级的唤醒调用的触发器。例如，执行 SELECT 语句会显示 SQL Server 使用表扫描获得数据。或者，如果确定索引是从表中检索数据的更快方法，则可能已转而使用索引扫描。

SHOWPLAN_TEXT 和 SHOWPLAN_ALL 语句返回的结果是树结构的表格形式表示（行和列）。执行计划树结构在结果集中使用一行表示树上的一个节点，每个节点代表一个逻辑或物理运算符，用于操作数据以产生预期的结果。而 SQL 查询分析器以图形方式将每个逻辑运算符和物理运算符显示为图标。有关更多信息，请参见逻辑运算符和物理运算符。


使用 SQL 查询分析器以图形方式显示执行计划

SQL 查询分析器是交互式图形工具，它使数据库管理员或开发人员能够编写查询、同时执行多个查询、查看结果、分析查询计划和获得提高查询性能的帮助。"执行计划"选项以图形方式显示 Microsoft® SQL Server™ 2000 查询优化器所选择的数据检索方法。图形执行计划使用图标表示 SQL Server 内特定语句和查询的执行，而不是使用 SET SHOWPLAN_ALL 或 SET SHOWPLAN_TEXT 语句生成的表格形式表示。这对了解查询的性能特点很有用。另外，SQL 查询分析器针对非索引列上的附加索引和统计提出建议，以提高查询优化器高效处理查询的能力。具体说来，SQL 查询分析器显示丢失了哪些统计信息，并因此强制查询优化器估计谓词选择性，然后使得很容易创建那些缺少的统计信息。

图形执行计划内显示的下列图标表示 SQL Server 执行语句所使用的物理运算符。有关更多信息，请参见逻辑运算符和物理运算符。

图标 | 物理运算符
 | Assert
 | Bookmark Lookup
 | Clustered Index Delete
 | Clustered Index Insert
 | Clustered Index Scan
 | Clustered Index Seek
 | Clustered Index Update
 | Collapse
 | Compute Scalar
 | Concatenation
 | Constant Scan
 | Deleted Scan
 | Filter (clsColumn)
 | Hash Match
 | Hash Match Root
 | Hash Match Team
 | Index Delete
 | Index Insert
 | Index Scan
 | Index Seek
 | Index Spool
 | Index Update
 | Inserted Scan
 | Log Row Scan
 | Merge Join
 | Nested Loops
 | Parallelism
 | Parameter Table Scan
 | Remote Delete
 | Remote Insert
 | Remote Query
 | Remote Scan
 | Remote Update
 | Row Count Spool
 | Sequence
 | Sort
 | Stream Aggregate
 | Table Delete
 | Table Insert
 | Table Scan
 | Table Spool
 | Table Update
 | Top

图形执行计划内显示的下列图标表示 SQL Server 执行语句所使用的游标物理运算符。

图标 | 游标物理运算符
 | Dynamic
 | Fetch Query
 | Keyset
 | Population Query
 | Refresh Query
 | Snapshot

读取图形执行计划输出

在 SQL 查询分析器中，从右到左、从上到下读取图形执行计划输出。将显示所分析的批处理内的每个查询，包括每个查询的成本占批处理总成本的百分比。

  • 树结构内的每个节点都用一个图标表示，指定用于执行部分查询或语句的逻辑运算符和物理运算符。

  • 每个节点都与一个父节点相关。所有具有相同父节点的节点都绘制在相同的列内。规则用箭头将每个节点连接到其父节点。

  • 递归操作用迭代符号显示。

  • 运算符显示为与特定父节点相关的符号。

  • 如果查询包含多个语句，则绘制多个查询执行计划。

  • 树结构的各部分由执行的语句类型决定。
语句类型 | 树结构元素
Transact-SQL 和存储过程 | 如果语句是存储过程或 Transact-SQL 语句，则成为图形执行计划树结构的根。存储过程可以有多个子代，这些子代表示由存储过程调用的语句。每个子代是树的一个节点或分支。
数据操作语言 (DML) | 如果由 SQL Server 查询优化器分析的语句是一个 DML 语句（如 SELECT、INSERT、DELETE 或 UPDATE），则该 DML 语句是树根。DML 语句最多可以有两个子代。第一个子代是 DML 语句的执行计划。如果用在语句内或由语句使用，第二个子代表触发器。
条件 | 图形执行计划将 IF...ELSE 语句这类条件语句（如果条件存在，转而执行后面的语句，否则执行此语句）划分为三个子代。IF...ELSE 语句是树根。If 条件成为子树节点。then 和 else 条件表示为语句块。使用相似的计划表示 WHILE 和 DO-UNTIL 语句。
关系运算符 | 由查询引擎执行的操作（如表扫描、联接和聚合）表示为树上的节点。
DECLARE CURSOR | DECLARE CURSOR 语句是图形执行计划树的根，与之相关的语句作为子代或节点。

当将游标指向每个节点时，该节点显示工具提示信息。工具提示信息可能包括：

  • 使用的物理运算符（物理操作），例如 Hash Join 或 Nested Loops。以红色显示的物理运算符表示查询优化器已发出警告，例如丢失列统计或丢失联接谓词。这可能导致查询优化器选择比预期的效率低的查询计划。有关列统计的更多信息，请参见统计信息。图形执行计划建议补救操作，例如创建或更新统计或者创建索引。使用 SQL 查询分析器的上下文菜单，可以立即创建或更新缺少的列统计和索引。

  • 与物理运算符匹配的逻辑运算符（逻辑操作），如 Join 运算符。如果逻辑运算符与物理运算符不同，将在工具提示的顶端列在物理运算符之后，并用正斜杠 (/) 分开。

  • 由运算符输出的行数（行计数）。

  • 由运算符输出的行的预计大小（预计行大小）。

  • 用于操作的所有 I/O 活动的预计成本（I/O 成本）。该值应尽可能低。

  • 用于操作的所有 CPU 活动的预计成本（CPU 成本）。

  • 查询时执行操作的次数（执行次数）。

  • 查询优化器执行此操作的成本（成本），包括此操作的成本占查询总成本的百分比。由于查询引擎选择最高效的操作执行查询或执行语句，因此该值应尽可能低。

  • 查询优化器执行此操作及同一子树内位于此操作之前的所有操作的总成本（子树成本）。

  • 查询所使用的谓词和参数（参数）。

创建统计

查询分析器

查询分析器

更新统计

查询分析器

查询分析器

删除统计

查询分析器

查询分析器

创建新索引

查询分析器

查询分析器

修改索引

查询分析器

查询分析器

删除索引

查询分析器

查询分析器

请参见

SET SHOWPLAN_ALL

SET SHOWPLAN_TEXT


逻辑运算符和物理运算符

逻辑运算符和物理运算符描述查询或更新的执行方式。物理运算符描述用于处理语句的物理实现算法，如扫描聚集索引。执行查询或更新语句时，每一步都涉及物理运算符。逻辑运算符描述用于处理语句的关系代数操作，如执行聚合。并非所有处理查询或更新的步骤都涉及逻辑操作。


Assert

Assert 逻辑运算符和物理运算符验证条件。例如，它验证引用完整性或检查约束，或者确保标量子查询返回一行。Assert 运算符为每个输入行对 Argument 列中的表达式取值。如果对该表达式取 NULL 值，将由 Assert 运算符传递该行。如果对该表达式取非空值，将显示相应的错误。


Aggregate

Aggregate 逻辑运算符以一组列的形式将输入分组，并计算聚合表达式（MIN、MAX、SUM 等等）。

请参见

聚合函数


Bookmark Lookup

Bookmark Lookup 逻辑运算符和物理运算符使用书签（行 ID 或聚集键）在表或聚集索引内查找相应的行。Argument 列包含书签标志，用于在表或聚集索引内查找行。Argument 列还包含要查找的行所在的表或聚集索引的名称。如果 WITH PREFETCH 子句出现在 Argument 列内，则表示查询处理器已决定在表或聚集索引内查找书签时最好使用异步预提取（预读）。


Clustered Index Delete

Clustered Index Delete 物理运算符从 Argument 列内指定的聚集索引中删除行。如果 WHERE:() 谓词出现在 Argument 列内，则只删除满足该谓词的行。

请参见

使用聚集索引


Clustered Index Insert

Clustered Index Insert 物理运算符将行从其输入中插入 Argument 列内指定的聚集索引中。Argument 列还包含 SET:() 谓词，它表示每列所设置的值。

请参见

使用聚集索引


Clustered Index Update

Clustered Index Update 物理运算符更新 Argument 列内指定的聚集索引中的输入行。

如果 WHERE:() 谓词出现，则只更新满足该谓词的行。如果 SET:() 谓词出现，它表示每个已更新列所设置的值。如果 DEFINE:() 谓词出现，则列出该运算符定义的值。可以在 SET 子句中、该运算符内的其它位置和该查询内的其它位置引用这些值。

请参见

使用聚集索引


Clustered Index Scan

Clustered Index Scan 逻辑运算符和物理运算符扫描 Argument 列内指定的聚集索引。当可选 WHERE:() 谓词出现，则只返回满足该谓词的行。如果 Argument 列包含 ORDERED 子句，则表示查询处理器已请求按聚集索引排序行的顺序返回行输出。如果没有出现 ORDERED 子句，存储引擎将以最佳方式（不保证对输出排序）扫描索引。

请参见

使用聚集索引


Clustered Index Seek

Clustered Index Seek 逻辑运算符和物理运算符利用索引的查找能力从聚集索引中检索行。

Argument 列包含正在使用的聚集索引的名称和 SEEK:() 谓词的行。存储引擎使用索引只处理满足 SEEK:() 谓词的行。或者，还可以包含 WHERE:() 谓词，存储引擎为所有满足 SEEK:() 谓词的行对其进行取值（而不是使用索引进行此项操作）。

如果 Argument 列包含 ORDERED 子句，则表示查询处理器已决定必须按聚集索引排序行的顺序返回行。如果没有出现 ORDERED 子句，存储引擎将以最佳方式（不保证对输出排序）搜索索引。若允许输出保持顺序，则效率可能比生成非排序输出的效率低。

请参见

使用聚集索引


Collapse

Collapse 逻辑运算符和物理运算符优化更新处理操作。执行更新时，可以将该更新操作拆分（使用 Split 运算符）成删除和插入操作。如果 Argument 列包含 GROUP BY:() 谓词和分组的键列列表，则查询处理器按键列集分组以优化这些更新操作，比如删除对每行所做的任何暂时的、不必要的中间级更改。

请参见

Split


Compute Scalar

Compute Scalar 逻辑运算符和物理运算符对表达式取值以生成计算标量值，可以将该值返回给用户和/或在查询中的其它位置（如在筛选谓词或联接谓词中）引用该值。

请参见

函数


Concatenation

Concatenation 逻辑运算符和物理运算符扫描多个输入，并返回每个所扫描的行。


Constant Scan

Constant Scan 逻辑运算符和物理运算符在查询中引入一个常量行。它将返回零或一行，该行通常不包含列。Compute Scalar 运算符通常用于在由 Constant Scan 生成的行上添加列。

请参见

Compute Scalar


Cross Join

Cross Join 逻辑运算符将第一个（顶端）输入中的每行与第二个（底端）输入中的每行联接在一起。

请参见

使用交叉联接


Delete

Delete 逻辑运算符从对象中删除满足 Argument 列内可选谓词的行。

请参见

DELETE


Deleted Scan

Deleted Scan 逻辑运算符和物理运算符扫描触发器内已删除的表。

请参见

使用 inserted 和 deleted 表


Distinct

Distinct 逻辑运算符扫描输入并删除重复项。

请参见

使用 DISTINCT 消除重复项


Distinct Sort

Distinct Sort 逻辑运算符扫描输入、删除重复项并按 Argument 列的 DISTINCT ORDER BY:() 谓词所指定的列进行排序。

请参见

Distinct

使用 DISTINCT 消除重复项


Distribute Streams

Distribute Streams 逻辑运算符只用在并行查询计划中。Distribute Streams 运算符消耗记录的单个输入流并生成多个输出流。记录的内容和格式不更改。输入流中的每个记录出现在某个输出流中。该运算符在输出流中自动保留输入记录的相对顺序。通常情况下，使用哈希操作确定具体某个输入记录所属的输出流。

如果输出是分区的，则 Argument 列包含 PARTITION COLUMNS:() 谓词和分区列。

请参见

Gather Streams

并行查询处理

Parallelism

Repartition Streams


Eager Spool

Eager Spool 逻辑运算符消耗整个输入，将每行存储在 tempdb 数据库中存储的隐藏临时对象内。如果重绕该运算符（例如通过 Nested Loops 运算符重绕），但不需要任何重新绑定，则将使用假脱机数据，而不用重新扫描输入。如果需要重新绑定，则将废弃假脱机数据，并通过重新扫描（重新绑定的）输入重建假脱机对象。

Eager Spool 运算符将急速生成自己的假脱机文件。当假脱机的父运算符请求第一行时，假脱机运算符将消耗其输入运算符内的所有行并将这些行存储在假脱机中。

说明 生成假脱机文件的另一种方法是使用 Lazy Spool 运算符。


Filter

Filter 逻辑运算符和物理运算符扫描输入，只返回满足出现在 Argument 列内的筛选表达式（谓词）的行。


Flow Distinct

Flow Distinct 逻辑运算符扫描输入并删除重复项。虽然 Distinct 运算符在生成任何输出前消耗所有的输入，但 Flow Distinct 运算符在从输入获得行时返回每行（除非该行是一个重复项，若是这样则废弃该行）。

请参见

Distinct

使用 DISTINCT 消除重复项


Full Outer Join

Full Outer Join 逻辑运算符从第一个（顶端）输入中与第二个（底端）输入相联接的行中返回每个满足联接谓词的行。它还可以从下面的输入返回行：

  • 在第二个输入中没有匹配项的第一个输入。

  • 在第一个输入中没有匹配项的第二个输入。

不包含匹配值的输入将作为空值返回。

请参见

使用联接


Gather Streams

Gather Streams 逻辑运算符只用在并行查询计划中。Gather Streams 运算符消耗几个输入流并通过组合输入流生成单个记录输出流。记录的内容和格式不更改。如果该运算符保留顺序，则所有的输入流都必须有序。

如果输出有序，则 Argument 列包含 ORDER BY:() 谓词和要排序的列名。

请参见

Distribute Streams

并行查询处理

Parallelism

Repartition Streams


Hash Match

Hash Match 物理运算符通过计算其生成输入内每行的哈希值生成哈希表。HASH:() 谓词以及一个用于创建哈希值的列的列表出现在 Argument 列内。然后，该谓词为每个探测行（如果适用）计算哈希值（使用相同的哈希函数）并在哈希表内查找匹配项。如果驻留谓词出现（在 Argument 列内由 RESIDUAL:() 标识），行还必须满足该谓词才被视为匹配项。根据所执行的逻辑操作，行为稍有不同：

  • 对于联接，使用第一个（顶端）输入生成哈希表，使用第二个（底端）输入探测哈希表。按联接类型规定的模式输出匹配项（或不匹配项）。如果多个联接使用相同的联接列，这些操作将分组为一个哈希组。

  • 对于非重复或聚合运算符，使用输入生成哈希表（删除重复项并计算聚合表达式）。生成哈希表时，扫描该表并输出所有项。

  • 对于 union 运算符，使用第一个输入生成哈希表（删除重复项）。使用第二个输入（它必须没有重复项）探测哈希表，返回所有没有匹配项的行，然后扫描该哈希表并返回所有项。

请参见

Distinct

了解哈希联接

Hash Match Team

Union


Hash Match Root

Hash Match Root 物理运算符协调其下一级所有 Hash Match Team 运算符的操作。Hash Match Root 运算符及其下一级所有 Hash Match Team 运算符拥有共同的哈希函数和分区策略。Hash Match Root 运算符总是将输出返回给不是其组的成员的运算符。

请参见

Hash Match Team

了解哈希联接


Hash Match Team

Hash Match Team 物理运算符是连接的哈希运算符组的一部分，这些运算符拥有共同的哈希函数和分区策略。

请参见

Hash Match Root

了解哈希联接


Index Delete

Index Delete 物理运算符删除 Argument 列中指定的非聚集索引的输入行。如果 WHERE:() 谓词出现，则只删除满足该谓词的行。

请参见

DELETE

使用非聚集索引


Index Insert

Index Insert 物理运算符将行从它的输入插入到 Argument 列中指定的非聚集索引中。Argument 列还包含 SET:() 谓词，它表示每列所设置的值。

请参见

INSERT

使用非聚集索引


Index Scan

Index Scan 逻辑运算符和物理运算符从 Argument 列内指定的非聚集索引中检索所有行。如果一个可选的 WHERE:() 谓词出现在 Argument 列内，则只返回满足该谓词的行。

如果 Argument 列必须包含 ORDERED 子句，则表示查询处理器已决定按非聚集索引排序行的次序返回行。如果 ORDERED 子句没有出现，存储引擎将以最佳方式（不保证对输出排序）搜索索引。

请参见

SELECT

使用非聚集索引


Index Seek

Index Seek 逻辑运算符和物理运算符利用索引的查找能力从非聚集索引中检索行。

Argument 列包含所使用的非聚集索引名称。它还包含 SEEK:() 谓词谓词的行。存储引擎使用索引只处理那些满足 SEEK:() 谓词的行。或者，还可以包含 WHERE:() 谓词，存储引擎将为满足 SEEK:() 谓词的行对其进行取值（而不是使用索引进行此项操作）。

如果 Argument 列包含 ORDERED 子句，则表示查询处理器已决定必须按非聚集索引排序行的顺序返回行。如果 ORDERED 子句没有出现，存储引擎将以最佳方式（不保证对输出排序）搜索索引。若允许输出保持顺序，则效率可能比生成非排序输出的效率低。

请参见

SELECT

使用非聚集索引


Index Spool

Index Spool 物理运算符包含 Argument 列中的 SEEK:() 谓词。Index Spool 运算符扫描其输入行，将每行的一个复本放在隐藏的假脱机文件（存储在 tempdb 数据库内并只在查询的生存周期内存在）中，并在这些行上生成索引。这使您得以利用索引的查找能力只输出那些满足 SEEK:() 谓词的行。

如果重绕该运算符（例如通过 Nested Loops 运算符重绕），但不需要任何重新绑定，则将使用假脱机数据，而不用重新扫描输入。

请参见

创建索引


Index Update

Index Update 物理运算符更新 Argument 列内指定的非聚集索引中的输入行。

如果 WHERE:() 谓词出现，则只更新满足该谓词的行。如果 SET:() 谓词出现，它表示每个已更新列所设置的值。如果 DEFINE:() 谓词出现，则列出该运算符定义的值。这些值可以在 SET 子句中、在该运算符内的其它位置和该查询内的其它位置引用。

请参见

UPDATE

使用非聚集索引


Inner Join

Inner Join 逻辑运算符返回满足第一个（顶端）输入与第二个（底端）输入联接的每一行。

请参见

使用内联接


Insert

Insert 逻辑运算符将每行从其输入插入 Argument 列内指定的对象中。该物理运算符可以是 Table Insert、Index Insert 或 Clustered Index Insert 运算符。

请参见

Clustered Index Insert

Table Insert

Index Insert


Inserted Scan

Inserted Scan 逻辑运算符和物理运算符扫描在触发器内插入的表。

请参见

使用 inserted 和 deleted 表


Lazy Spool

Lazy Spool 逻辑运算符将每行从其输入存储到 tempdb 数据库内存储的隐藏临时对象中。如果重绕该运算符（例如通过 Nested Loops 运算符重绕），但不需要任何重新绑定，则将使用假脱机数据，而不用重新扫描输入。如果需要重新绑定，则将废弃假脱机数据，并通过重新扫描（重新绑定的）输入重建假脱机对象。

Lazy Spool 运算符将以慢性（不急速）方式生成其假脱机文件。每当假脱机父运算符请求一行时，假脱机运算符便从其输入运算符获得一行，然后将该行存储在假脱机中。

请参见

Eager Spool


Left Anti Semi Join

当第二个（底端）输入中没有匹配行时，Left Anti Semi Join 逻辑运算符返回第一个（顶端）输入中的每一行。如果 Argument 列内不存在任何联接谓词，则每行都是一个匹配行。

请参见

使用联接


Left Outer Join

Left Outer Join 逻辑运算符返回每个满足第一个（顶端）输入与第二个（底端）输入的联接的行。它还返回任何在第二个输入中没有匹配行的第一个输入中的行。第二个输入中的非匹配行作为空值返回。如果 Argument 列内不存在任何联接谓词，则每行都是一个匹配行。

请参见

使用联接


Left Semi Join

当第二个（底端）输入中有匹配行时，Left Semi Join 逻辑运算符返回第一个（顶端）输入中的每行。如果 Argument 列内不存在任何联接谓词，则每行都是一个匹配行。

请参见

使用联接


Log Row Scan

Log Row Scan 逻辑运算符和物理运算符扫描事务日志。

请参见

事务日志


Merge Interval

Merge Interval 逻辑运算符和物理运算符合并多个（可能交叠的）间隔以生成最小的非交叠间隔，然后用于查找索引项。该运算符一般出现在 Constant Scan 运算符上的一个或多个 Compute Scalar 运算符上方，这些运算符构造了 Merge Interval 运算符所合并的间隔（表示为一行中的列）。

请参见

Compute Scalar

Constant Scan


Merge Join

Merge Join 物理运算符执行 Inner Join、Left Outer Join、Left Semi Join、Left Anti Semi Join、Right Outer Join、Right Semi Join、Right Anti Semi Join 和 Union 逻辑操作。

在 Argument 列内，如果操作执行的是一到多联接，则 Merge Join 运算符包含 MERGE:() 谓词；如果操作执行的是多到多联接，则包含 MANY-TO-MANY MERGE:() 谓词。Argument 列还包含一个用于执行操作的列的用逗号分隔的列表。Merge Join 运算符要求两个输入在各自的列上排序，这可以通过在查询计划中插入显式排序操作实现。如果不需要显式排序，例如，如果数据库内有适宜的 B 树索引，或者如果可以对多个操作（如合并联接和对汇总分组）使用排序次序，则合并联接尤其有效。

请参见

了解合并联接


Nested Loops

Nested Loops 物理运算符执行 Inner Join、Left Outer Join、Left Semi Join 和 Left Anti Semi Join 逻辑操作。

嵌套循环联接一般使用索引在内表上搜索外表的每行。根据预期的成本，Microsoft® SQL Server™ 2000 决定是否对外输入排序以便在内输入上提高索引搜索的定位准确性。

返回任何满足 Argument 列内的（可选）谓词的行（其可行性基于所执行的逻辑操作）。

请参见

了解嵌套循环联接


Parallelism

Parallelism 物理运算符执行 Distribute Streams、Gather Streams 和 Repartition Streams 逻辑运算。Argument 列可以包含 PARTITION COLUMNS:() 谓词和一个用逗号分隔的分区列的列表。Argument 列还可以包含 ORDER BY:() 谓词和一个在分区时保留排序次序的列的列表。

请参见

Distribute Streams

Repartition Streams

Gather Streams


Parameter Table Scan

Parameter Table Scan 逻辑运算符和物理运算符扫描在当前查询中用作参数的表。该运算符一般用于存储过程内的 INSERT 查询。

请参见

INSERT


Remote Delete

Remote Delete 逻辑运算符和物理运算符删除远程对象中的输入行。


Remote Insert

Remote Insert 逻辑运算符和物理运算符将输入行插入到远程对象中。


Remote Query

Remote Query 逻辑运算符和物理运算符将查询提交给远程源。发送给远程服务器的查询文本出现在 Argument 列内。

请参见

优化分布式查询


Remote Scan

Remote Scan 逻辑运算符和物理运算符扫描远程对象。远程对象的名称出现在 Argument 列内。


Remote Update

Remote Update 逻辑运算符和物理运算符更新远程对象中的输入行。


Repartition Streams

Repartition Streams 逻辑运算符只在并行查询计划中使用。Repartition Streams 运算符消耗多个流并生成多个记录流。记录的内容和格式不更改。输入流中的每个记录都放入一个输出流中。如果该运算符保留次序，则必须对所有输入流排序并将它们合并到几个有序的输出流中。

如果输出是分区的，则 Argument 列包含 PARTITION COLUMNS:() 谓词和分区列。

如果输出有序，则 Argument 列包含 ORDER BY:() 谓词和要排序的列。

请参见

Distribute Streams

并行查询处理

Gather Streams


Right Anti Semi Join

当第一个（顶端）输入中没有匹配行时，Right Anti Semi Join 逻辑运算符将输出第二个（底端）输入中的每行。匹配行的定义是满足 Argument 列内的谓词的行（如果不存在谓词，则每行都是一个匹配行）。

请参见

使用联接


Right Outer Join

Right Outer Join 逻辑运算符返回满足第二个（底端）输入与第一个（顶端）输入中的每个匹配行联接的每一行。它还返回第二个输入中在第一输入中没有匹配行的任何行，即与 NULL 联接。如果 Argument 列内不存在任何联接谓词，则每行都是一个匹配行。

请参见

使用联接


Right Semi Join

当第一个（顶端）输入中有匹配行时，Right Semi Join 逻辑运算符返回第二个（底端）输入中的每行。如果 Argument 列内不存在任何联接谓词，则每行都是一个匹配行。

请参见

使用联接


Row Count Spool

Row Count Spool 物理运算符扫描输入，对存在的行进行计数并返回不包含任何数据的行。当检查行的存在比检查行中包含的数据更重要时，则使用该运算符。例如，如果 Nested Loops 运算符执行左半联接操作且联接谓词适用于内输入，则可以在 Nested Loops 运算符的内输入顶端放置行计数假脱机。这样，Nested Loops 运算符就可以查看行计数假脱机输出了多少行（因为不需要内侧的实际数据）以决定是否返回外部行。

请参见

Left Semi Join

Nested Loops


Sequence

Sequence 逻辑运算符和物理运算符驱动大范围的更新计划。就其功能而言，该运算符按顺序（从上到下）执行每个输入。每个输入通常是不同对象的更新。该运算符只返回其上一个（底端）输入中的行。


Sort

Sort 逻辑运算符和物理运算符对所有外来行排序。Argument 列包含 DISTINCT ORDER BY:() 谓词（如果该操作删除重复项），或者包含 ORDER BY:() 谓词和一个所排序的列的逗号分隔列表。如果按升序对列排序，则使用值 ASC 作为列的前缀；如果按降序对列排序，则使用值 DESC 作为列的前缀。

请参见

SELECT


Split

Split 逻辑运算符和物理运算符用于优化更新处理操作。它将每个更新操作拆分成删除和插入操作。

请参见

Collapse


Stream Aggregate

Stream Aggregate 物理运算符可以选择按一组列分组，并计算由查询返回的和/或查询内的其它位置所引用的一个或多个聚合表达式。该运算符要求输入在组中按列排序。

如果 Stream Aggregate 运算符按列分组，则 GROUP BY:() 谓词和列的列表将出现在 Argument 列内。如果 Stream Aggregate 运算符计算聚合表达式，则这些表达式的列表将出现在 SHOWPLAN_ALL 语句输出的 Defined Values 列中或图形执行计划的 Argument 列中。

请参见

聚合函数


Table Delete

Table Delete 物理运算符删除参数列内指定的表中的行。如果 WHERE:() 谓词出现在 Argument 列内，则只删除满足该谓词的行。

请参见

DELETE


Table Insert

Table Insert 物理运算符将行从其输入插入 Argument 列内指定的表中。Argument 列还包含 SET:() 谓词，它表示每列所设置的值。

请参见

INSERT


Table Scan

Table Scan 逻辑运算符和物理运算符检索 Argument 列内指定表中的所有行。如果 WHERE:() 谓词出现在 Argument 列内，则只返回满足该谓词的行。

请参见

SELECT


Table Spool

Table Spool 物理运算符扫描输入并将每行的复本放在隐藏假脱机表（存储在 tempdb 数据库内并只在查询的生存周期内存在）中。如果重绕该运算符（例如通过 Nested Loops 运算符重绕），但不需要任何重新绑定，则将使用假脱机数据，而不用重新扫描输入。


Table Update

Table Update 物理运算符更新 Argument 列内指定表中的输入行。如果 WHERE:() 谓词出现，则只更新满足该谓词的行。如果 SET:() 谓词出现，它表示每个已更新列所设置的值。如果 DEFINE:() 谓词出现，则列出该运算符定义的值。可以在 SET 子句中、该运算符内的其它位置和该查询内的其它位置引用这些值。

请参见

UPDATE


Top

Top 逻辑运算符和物理运算符扫描输入，从顶端开始返回指定数目或百分比数目的行。Argument 列可以选择包含要为结而检查的列的列表。在更新计划中，Top 运算符用于强制行计数限制。

请参见

使用 TOP 和 PERCENT 限制结果集

SET ROWCOUNT


Union

Union 逻辑运算符扫描多个输入，输出每个已扫描的行并删除重复项。

请参见

UNION


Update

Update 逻辑运算符更新 Argument 列内指定对象的输入中的每行。物理运算符是 Table Update、Index Update 或 Clustered Index Update。

请参见

UPDATE


游标逻辑运算符和物理运算符

游标逻辑运算符和物理运算符用于描述涉及游标操作的查询或更新的执行方式。其中物理运算符描述用于处理游标（如使用键集驱动游标）的物理实现算法。游标执行过程的每一步都涉及物理运算符。而逻辑运算符描述游标的属性，如游标是只读。

逻辑运算符

游标逻辑运算符包括：

Asynchronous

异步填充游标表。有关更多信息，请参见异步填充。

Optimistic

该游标使用乐观并发模式。有关更多信息，请参见游标并发。

Primary

这是该游标的主要提取查询。

Read Only

该游标对并发应用只读语义。该游标只能读取数据，不能插入、更新或删除数据。有关更多信息，请参见游标并发。

Scroll Locks

该游标对并发应用滚动锁。有关更多信息，请参见游标并发。

Secondary

这是辅助提取查询（在主要提取查询失败时使用）。

Synchronous

同步填充游标表。

物理运算符

游标物理运算符包括：

Dynamic

该游标可以发现其它游标所做的任何更改。有关更多信息，请参见动态游标。

Fetch Query

该查询在对游标发出提取请求时检索行。

Keyset

该游标可以发现其它游标所做的更新，但无法发现插入。有关更多信息，请参见键集驱动游标。

Population Query

该查询在游标打开时填写该游标的工作表。

Refresh Query

该查询为游标提取缓冲区中的行提取当前数据。

快照

该游标无法发现其它游标所做的更改。有关更多信息，请参见静态游标。

请参见

游标


查询优化建议

有些查询天生就消耗大量资源。这与基本的数据库和索引问题有关。这些查询的效率并不低，因为查询优化器会以最有效的可能方式实现这些查询。然而，它们确实消耗大量资源，而且 Transact-SQL 面向集合的性质使这些查询看起来效率很低。查询优化器的智能水平无法消除这些构造的固有资源成本。与不复杂的查询相比，这些查询的固有成本十分昂贵。虽然 Microsoft® SQL Server™ 2000 使用最佳的访问计划，但受到基础构造可能性的限制。例如，下列类型的查询可能占用大量资源：

  • 返回大结果集的查询

  • 高度不唯一的 WHERE 子句

不过有一些针对优化查询和提高查询性能的建议，其中包括：

  • 添加更多的内存（尤其是如果服务器运行许多复杂查询而且其中几个查询执行很慢）。

  • 在有多个处理器的计算机上运行 SQL Server。多个处理器使 SQL Server 得以利用并行查询。有关更多信息，请参见并行查询处理。

  • 考虑重新编写查询。
    • 如果查询使用游标，则确定如果使用效率更高的游标类型（如快速只进游标）或单纯查询能否更有效地编写游标查询。单纯查询的性能一般优于游标操作。一组游标语句通常是一个外循环操作，在此操作中，一旦使用内部语句便开始处理外循环内的每行，因此可考虑使用 GROUP BY 或 CASE 语句或改为使用子查询。

    • 如果应用程序使用循环，可考虑在查询内放入循环。应用程序常包含带参数化查询的循环，该循环执行许多次并要求运行应用程序的计算机与 SQL Server 之间有网络往返。可改为使用临时表创建一个更复杂的查询。只需提供一个网络往返，查询优化器即会更好地优化这个查询。

    • 不要对同一查询内的单个表使用多个别名以模拟索引交叉。模拟索引交叉已没有必要，因为 SQL Server 会自动考虑索引交叉并且可以在同一查询内的相同表上使用多个索引。例如，给出下列示例查询：
      SELECT * FROM lineitem
WHERE partkey BETWEEN 17000 AND 17100 AND
      shipdate BETWEEN '1/1/1994' AND '1/31/1994"

      SQL Server 可以在 partkey 和 shipdate 列上都使用索引，然后在两个子集之间执行哈希匹配以获得索引交叉。

    • 只在必要时才使用查询提示。若查询使用在 SQL Server 早期版本上执行的提示，则应在不指定提示的情况下对该查询进行测试。提示会防碍查询优化器选择更好的执行计划。有关更多信息，请参见 SELECT。
  • 利用 query governor 配置选项和设置。可以使用 query governor 配置选项阻止执行长时间运行的查询，从而防止消耗系统资源。默认情况下，query governor 配置选项允许执行所有查询，而不考虑查询所需的时间。然而，可以将查询调控器设置到最大秒数，以允许执行所有连接的所有查询或只允许执行特定连接的查询。查询调控器基于估计的查询成本而不是实际的已用时间，因此没有任何运行时开销。它还在长时间运行的查询开始前便将其停止，而不是先运行这些查询直到达到某些预定义的限制为止。有关更多信息，请参见 query governor cost limit 选项和 SET QUERY_GOVERNOR_COST_LIMIT。

请参见

CASE

子查询基础知识

GROUP BY 组件


高级查询优化概念

Microsoft® SQL Server™ 2000 使用内存中的排序和哈希联接技术执行排序、交集、联合、差分等操作。SQL Server 利用这种类型的查询计划支持垂直表分区，有时称其为分列存储。

SQL Server 使用三种类型的联接操作：

  • 嵌套循环联接

  • 合并联接

  • 哈希联接

如果一个联接输入很小（比如不到 10 行），而另一个联接输入很大而且已在其联接列上创建索引，则索引嵌套循环是最快的联接操作，因为它们需要最少的 I/O 和最少的比较。有关嵌套循环的更多信息，请参见了解嵌套循环联接。

如果两个联接输入并不小但已在二者联接列上排序（例如，如果它们是通过扫描已排序的索引获得的），则合并联接是最快的联接操作。如果两个联接输入都很大，而且这两个输入的大小差不多，则预先排序的合并联接提供的性能与哈希联接相似。然而，如果两个输入的大小相差很大，则哈希联接操作通常快得多。有关更多信息，请参见了解合并联接。

哈希联接可以有效处理很大的、未排序的非索引输入。它们对复杂查询的中间结果很有用，因为：

  • 中间结果未经索引（除非已经显式保存到磁盘上然后创建索引），而且生成时通常不为查询计划中的下一个操作进行适当的排序。

  • 查询优化器只估计中间结果的大小。由于估计的值在复杂查询中可能有很大的误差，因此如果中间结果比预期的大得多，则处理中间结果的算法不仅必须有效而且必须适度弱化。

哈希联接使得对非规范化的使用减少。非规范化一般通过减少联接操作获得更好的性能，尽管这样做有冗余之险（如不一致的更新）。哈希联接则减少使用非规范化的需要。哈希联接使垂直分区（用单独的文件或索引代表单个表中的几组列）得以成为物理数据库设计的可行选项。有关更多信息，请参见了解哈希联接。


了解嵌套循环联接

嵌套循环联接也称为嵌套迭代，它将一个联接输入用作外部输入表（显示为图形执行计划中的顶端输入），将另一个联接输入用作内部（底端）输入表。外部循环逐行消耗外部输入表。内部循环为每个外部行执行，在内部输入表中搜索匹配行。最简单的情况是，搜索时扫描整个表或索引；这称为单纯嵌套循环联接。如果搜索时使用索引，则称为索引嵌套循环联接。如果将索引生成为查询计划的一部分（并在查询完成后立即将索引破坏），则称为临时索引嵌套循环联接。查询优化器考虑所有这些不同形式。如果外部输入很小而内部输入很大且预先创建了索引，则嵌套循环联接尤其有效。在许多小事务中（如那些只影响较小的一组行的事务），索引嵌套循环联接远比合并联接和哈希联接优越。但在大查询中，嵌套循环联接通常不是最佳选择。


了解合并联接

合并联接要求两个输入都在合并列上排序，而合并列由联接谓词的等效 (WHERE) 子句定义。查询优化器一般扫描索引（如果在适当的一组列上存在一个索引），或在合并联接的下面放一个排序运算符。在很少的情况下，虽然可能有多个等效子句，但只用其中一些可用的等效子句获得合并列。

由于每个输入都已排序，Merge Join 运算符将获取每个输入中的行并将其进行比较。例如，对于内联接操作，如果行相等则返回。如果行不相等，则废弃值较小的行并从该输入中获得另一行。这一过程将重复进行，直到处理完所有的行为止。

合并联接操作可以是常规操作，也可以是多对多操作。多对多合并联接使用临时表存储行。如果每个输入中有重复值，则在处理其中一个输入中的每个重复项时，另一个输入必须重绕到重复项的开始位置。

如果存在驻留谓词，所有满足合并谓词的行都将对该驻留谓词取值，然后只返回那些满足该驻留谓词的行。

合并联接本身的速度很快，但如果需要排序操作，选择合并联接就会非常费时。然而，如果数据量很大且能够从现有 B 树索引中获得预排序的所需数据，则合并联接通常是最快的可用联接算法。


了解哈希联接

哈希联接有两种输入：生成输入和探测输入。查询优化器指派这些角色，使两个输入中较小的那个作为生成输入。

哈希联接可用于许多类型的集合匹配操作：内联接，左向外联接、右向外联接和完整外联接，左向半联接和右向半联接、交集、联合和差分。而且，哈希联接的变化形式能够进行重复项删除和分组操作（如 SUM(salary) GROUP BY department）。这些修改对生成和探测角色只使用一个输入。

与合并联接相似，只有当联接谓词中至少有一个等效 (WHERE) 子句时才能使用哈希联接。然而，联接一般用于重组合由主键和外键之间的等效谓词表达的关系，因此大多数联接至少有一个等效子句。用等效谓词表达的列集合称为哈希键，因为这些列有助于哈希函数。还可以有附加的谓词，并且可以将这些谓词取值为驻留谓词以与哈希值比较分开。哈希键可以是表达式，只要能从单个行中的列对其进行排它计算。在分组操作中，按列表分组的列是哈希键。在交集等集合操作中以及删除复制项时，哈希键由所有列组成。

内存中的哈希联接

哈希联接先扫描或计算整个生成输入，然后在内存中生成哈希表。根据为哈希键计算出的哈希值，将每行插入哈希存储桶。如果整个生成输入比可用内存少，则可以将所有行都插入哈希表中。生成阶段后接着是探测阶段。一次一行地对整个探测输入进行扫描或计算，并为每个探测行计算哈希键的值，扫描相应的哈希存储桶并生成匹配项。

Grace 哈希联接

如果生成输入不适合内存，哈希联接将分步进行。每一步都包括生成阶段和探测阶段。首先，消耗整个生成和探测输入并（使用哈希键上的哈希函数）将其分区为多个文件。这类文件的数目称为分区输出端。通过使用哈希键上的哈希函数，可以保证任意两个联接记录必在相同的文件对中。因此，联接两个大输入的任务简化为相同任务的多个较小的实例。然后将哈希联接应用于每对分区文件。

递归哈希联接

如果生成输入非常大，以至于标准外部合并排序的输入需要多个合并级别，则需要多个分区步骤和多个分区级别。如果只有某些分区较大，则只需对这些分区使用附加的分区步骤。为使所有的分区步骤尽可能快，将使用大的异步 I/O 操作以便单个线程就能使多个磁盘驱动器繁忙工作。

说明 如果生成输入较大但并不比可用内存大很多，则内存中的哈希联接和 Grace 哈希联接的元素将合并成一个步骤，产生混合哈希联接。

在优化过程中并不总能确定使用什么样的哈希联接。因此，Microsoft® SQL Server™ 2000 开始时使用内存中的哈希联接，然后根据生成输入的大小逐渐转换到 Grace 哈希联接和递归哈希联接。

如果优化器错误地预计两个输入中哪个较小并由此确定哪个作为生成输入，生成角色和探测角色将动态逆转。哈希联接确保使用较小的溢出文件作为生成输入。这一技术称为角色逆转。


应用程序设计

应用程序设计在决定使用 Microsoft® SQL Server™ 2000 的系统的性能方面起关键作用。将客户端视为控制实体而非数据库服务器。客户端确定查询类型、何时提交查询以及如何处理查询结果。这反过来对服务器上的锁类型和持续时间、I/O 活动量以及处理 (CPU) 负荷等产生主要影响，并由此影响总体性能的优劣。

正因为如此，在应用程序的设计阶段做出正确决策十分重要。然而，即使在使用总控应用程序时（这种情况下似乎不可能更改客户端应用程序）出现性能问题，也不会改变影响性能的根本因素：客户端具有支配作用，如果不更改客户端则许多性能问题都无法解决。设计优秀的应用程序允许 SQL Server 支持成千上万的并发用户。反之，设计差的应用程序会防碍即使是最强大的服务器平台处理少数用户的请求。

客户端应用程序的设计准则包括：

  • 消除过多的网络流量。

    客户端和 SQL Server 之间的网络往返通常是数据库应用程序性能较差的首要原因，甚至超过了服务器和客户端之间传送的数据量这一因素的影响。网络往返描述在客户端应用程序和 SQL Server 之间为每个批处理和结果集发送的会话流量。通过使用存储过程，可以将网络往返减到最小。例如，如果应用程序根据从 SQL Server 收到的数据值采取不同的操作，只要可能就应直接在存储过程中做出决定，从而消除过多的网络流量。

    如果存储过程中有多个语句，则默认情况下，SQL Server 在每个语句完成时给客户端应用程序发送一条消息，详细说明每个语句所影响的行数。大多数应用程序不需要这些消息。如果确信应用程序不需要它们，可以禁用这些消息，以提高慢速网络的性能。请使用 SET NOCOUNT 会话设置为应用程序禁用这些消息。有关更多信息，请参见 SET NOCOUNT。

  • 使用小结果集。

    检索没必要大的结果集（如包含上千行）并在客户端浏览将增加 CPU 和网络 I/O 的负载，使应用程序的远程使用能力降低并限制多用户可伸缩性。最好将应用程序设计为提示用户输入足够的信息，以便查询提交后生成大小适中的结果集。有关更多信息，请参见使用高效数据检索优化应用程序性能。

    可帮助实现上述目标的应用程序设计技术包括：在生成查询时对通配符进行控制，强制某些输入字段，不允许特殊查询，以及使用 TOP、PERCENT 或 SET ROWCOUNT 等 Transact-SQL 语句限制查询返回的行数。有关更多信息，请参见使用 TOP 和 PERCENT 限制结果集和 SET ROWCOUNT。

  • 允许在用户需要重新控制应用程序时取消正在执行的查询。

    应用程序决不应强迫用户重新启动客户机以取消查询。无视这一点将导致无法解决的性能问题。如果应用程序取消查询（例如使用开放式数据库连接 (ODBC) sqlcancel 函数取消查询），应对事务级别予以适当的考虑。例如，取消查询并不会提交或回滚用户定义的事务。取消查询后，所有在事务内获取的锁都将保留。因此，在取消查询后始终要提交或回滚事务。同样的情况也适用于可用于取消查询的 DB-Library 和其它应用程序接口 (API)。

  • 始终实现查询或锁定超时。

    不要让查询无限期运行。调用适当的 API 以设置查询超时。例如，使用 ODBC SQLSetStmtOption 函数。

    有关设置查询超时的更多信息，请参见 ODBC API 文档。

    有关设置锁定超时的更多信息，请参见自定义锁超时。

  • 不要使用不允许显式控制发送到 SQL Server 的 SQL 语句的应用程序开发工具。

    如果工具基于更高级的对象透明地生成 Transact-SQL 语句，而且不提供诸如查询取消、查询超时和完全事务控制等关键功能，则不要使用这类工具。如果应用程序生成透明的 SQL 语句，通常不可能维护好的性能或解决性能问题，因为在这种情况下不允许对事务和锁定问题进行显式控制，而这一点对性能状况至关重要。

  • 不要将决策支持和联机事务处理 (OLTP) 查询混在一起。有关更多信息，请参见联机事务处理与决策支持。

  • 只在必要时才使用游标。

    游标是关系数据库中的有用工具，但使用游标完成任务始终比使用面向集合的 SQL 语句花费多。

    当使用面向集合的 SQL 语句时，客户端应用程序让服务器更新满足指定条件的记录集。服务器决定如何作为单个工作单元完成更新。当通过游标更新时，客户端应用程序要求服务器为每行维护行锁或版本信息，而这只是为了客户端在提取行后请求更新行。

    而且，使用游标意味着服务器通常要在临时存储中维护客户端的状态信息，如用户在服务器上的当前行集。为众多客户端维护这类状态信息需消耗大量的服务器资源。对于关系数据库，更好的策略是让客户端应用程序快速进出，以便在各次调用之间不在服务器上维护客户端的状态信息。面向集合的 SQL 语句支持此策略。

    然而，如果查询使用游标，请确定如果使用更高效的游标类型（如快速只进游标）或单个查询能否更高效地编写游标查询。有关更多信息，请参见使用高效数据检索优化应用程序性能。

  • 使事务尽可能简短。有关更多信息，请参见事务和批处理对应用程序性能的影响。

  • 使用存储过程。有关更多信息，请参见存储过程对应用程序性能的影响。

  • 使用 Prepared Execution 来执行参数化 SQL 语句。有关更多信息，请参见 Prepared Execution (ODBC)。

  • 始终处理完所有结果。

    不要设计或使用在未取消查询时就停止处理结果行的应用程序。否则通常会导致阻塞和降低性能。有关更多信息，请参见了解和避免阻塞。

  • 确保将应用程序设计为可避免死锁。有关更多信息，请参见将死锁减至最少。

  • 确保已设置所有能够优化分布式查询性能的适当选项。有关更多信息，请参见优化分布式查询。

请参见

死锁

锁定

动态锁定

事务


网络和性能

客户端/服务器数据库的一个主要特征是对相关的网络流量有限制。许多使用 Microsoft® SQL Server™ 2000 的应用程序允许用户通过调制解调器链接登录后仍有效地使用该应用程序。虽然与局域网 (LAN) 相比，网络 I/O 性能降低了 1,000 因子，但通常很少有性能降低的迹象。不过，如果在客户端和服务器之间传输大量的数据，网络性能则会受到负面影响。

最好是监视客户端应用程序与服务器之间的流通。为慢速网络设计和优化的应用程序在快速网络上能够很好地运行，但反过来则不是这样。如果使用更高级的开发工具生成 Transact-SQL 语句并代表自己发出查询和更新，那么监视网络流通状况尤其重要。


命名管道与 TCP/IP 套接字

在快速局域网 (LAN) 环境中，传输控制协议或 Internet 协议 (TCP/IP) 套接字客户端和命名管道客户端在性能方面不相上下。但是，网络速度越慢（如在广域网 (WAN) 或拨号网络上），TCP/IP 套接字客户端与命名管道客户端的性能差异越明显。这是因为进程间通讯 (IPC) 机制在对等项间的通讯方法不同。

对于命名管道，通常网络通信交互性更强。一个对等项直到另一个对等项使用读取命令请求数据时才发送数据。在开始读取数据前，网络读取一般包括一系列窥视命名管道的信息。这在慢速网络中可能花费非常多并导致过多的网络流量，其它的网络客户端反过来也会受到影响。

阐明所讨论的是本地管道还是网络管道也很重要。如果服务器应用程序在运行 Microsoft® SQL Server® 2000 实例的计算机上本地运行，则可以选择本地命名管道协议。本地命名管道以内核模式运行且速度非常快。

对于 TCP/IP 套接字，数据传输的效率更高，开销也更少。数据传输还可以利用 TCP/IP 套接字性能增强机制的优点，如开窗口、延迟确认等，这在慢速网络中可能非常有益。对于应用程序的不同类型，这类性能差异可能非常大。

TCP/IP 套接字还支持待办事项队列，当试图连接到 SQL Server 时，与可能导致管道忙错误的命名管道相比，该队列可以提供有限的平稳效果。

一般情况下，套接字在慢速 LAN、WAN 或拨号网络中效果较佳，而当网络速度不成问题时命名管道则是更好的选择，因为其功能更强、易于使用且提供多种配置选项。

有关 TCP/IP 的更多信息，请参见 Microsoft Windows NT® 文档。

请参见

客户端 Net-Library 和网络协议


使用高效数据检索优化应用程序性能

SQL 语言的功能之一是能够在服务器上筛选数据，以便只给客户端返回最少的所需数据。使用这些功能可使服务器与客户端间的高耗费的网络流量减到最小。这意味着必须使 WHERE 子句的限制性足够强，从而使其只检索应用程序所需的数据。

若是在服务器上筛选数据，则效率始终会高于将数据发送到客户端、然后在应用程序中筛选数据。这种情况也适用于从服务器请求的列。发出 SELECT * FROM... 语句的应用程序要求服务器将所有列数据返回给客户端，不论客户端应用程序是否已绑定这些列以在程序变量中使用。按名称只选择必要的列可避免不必要的网络流量。这也使应用程序在表定义更改时更可靠，因为新添加的列不返回给客户端应用程序。

性能还取决于应用程序如何从服务器请求结果集。在使用开放式数据库连接 (ODBC) 的应用程序中，在执行查询前设置的语句选项决定应用程序如何从服务器请求结果集。当保留语句选项的默认值时，Microsoft® SQL Server™ 2000 以最有效的方式发送结果集。

SQL Server 假定应用程序立即从默认结果集中提取所有的行。因此，该应用程序必须缓冲那些不立即使用但以后可能需要的行。这种缓冲需求决定了（通过使用 Transact-SQL）仅指定所需的数据尤其重要。

请求默认结果集并只按应用程序逻辑或应用程序用户的需要提取行这一做法看起来很节省，但却是假节省。未从默认结果集中提取的行会阻碍与服务器的连接，并阻塞同一事务中的其它工作。另外，未从默认结果集中提取的行会导致 SQL Server 在服务器上控制锁，从而有可能防碍其他用户更新。在小规模测试中可能不会出现这种并发问题，但是以后部署应用程序时则会出现该问题。因此，应立即从默认结果集中提取所有的行。有关更多信息，请参见了解和避免阻塞。

有些应用程序无法缓冲它们从服务器请求的所有数据。例如，如果应用程序查询大表并允许用户指定选择条件，则可能不返回任何行或返回上百万行。而用户不大可能想查看上百万行。相反，用户更有可能缩小选择条件重新执行查询。在此情况下，提取和缓冲上百万行，而用户最终丢弃这些行，无疑是浪费时间和资源。

对于这些应用程序，SQL Server 提供服务器游标以允许应用程序从任意大的结果集中提取小的行子集或行块。如果用户想看到同一结果集内的其它记录，服务器游标允许应用程序从结果集中提取任何其它行块，包括结果集内后面的 n 行、前面的 n 行或从某行开始的 n 行。SQL Server 只根据需要执行每个块提取请求，而且 SQL Server 通常不在服务器游标上的块提取之间控制锁。

服务器游标还允许应用程序对提取的行执行定位更新或删除，而无须确定行的源表和主键。如果行数据从提取到请求更新的这段期间内更改，SQL Server 会检测出这个问题并防止丢失更新。

但是，服务器游标的功能需要一定的代价。如果给定查询的所有结果都要在应用程序中使用，则服务器游标总是比默认结果集消费高。默认结果集始终只需要在客户端和服务器间往返一次，而每次用服务器游标调用提取行块操作便导致一次往返。此外，服务器游标消耗服务器上的资源，对某些类型的游标可以使用的 SELECT 语句也有限制。例如，KEYSET 游标被限制为只能使用带唯一索引的表，而 KEYSET 和 STATIC 游标大量使用服务器上的临时存储。由于这些原因，只有应用程序需要服务器游标功能时才使用这些服务器游标。如果某个任务通过主键请求单个行，则使用默认结果集。如果另外一个任务需要大得无法预料的结果集或可更新的结果集，则使用服务器游标提取大小适中的块（例如一次提取一屏行）。另外，只要可能就应对自动提取使用快速只进游标。可以使用这些游标只在客户端和服务器之间往返一次而检索出小结果集，这与使用默认结果集相似。有关更多信息，请参见快速只进游标。

请参见

游标

SELECT


事务和批处理对应用程序性能的影响

适当使用 Transact-SQL 的主要目的是减少服务器与客户端之间传输的数据量。减少传输的数据量通常可缩短完成逻辑任务或事务所需的时间。长时间运行的事务对单个用户可能很好，但若扩展到多个用户则表现很差。为支持事务的一致性，数据库必须自最开始在事务内获取对共享资源的锁后，一直将该锁控制到事务提交为止。如果其他用户需要访问同一资源，则必须等待。随着个别事务变长，等待锁的队列和其他用户也变长，系统吞吐量随之减少。长事务还增加死锁的可能性，当两个或更多的用户同时等待互相控制的锁时会发生死锁。有关更多信息，请参见死锁。

可用于缩短事务持续时间的技术包括：

  • 在应用程序的要求内尽快提交事务更改。

    应用程序常将大的批处理作业（如月底汇总计算）作为单个工作单元（因此是一个事务）执行。在多数这类应用程序中，可以提交作业的各步骤，而不危及数据库的一致性。尽快提交更改意味着尽快释放锁。

  • 利用 Microsoft® SQL Server™ 2000 语句批处理。

    语句批处理是一种一次将多个 Transact-SQL 语句从客户端发送到 SQL Server 的方法，从而减少到服务器的网络往返次数。如果语句批处理包含多个 SELECT 语句，服务器将以单个数据流将多个结果集返回给客户端。

  • 对重复操作使用参数数组。

    例如，开放式数据库连接 (ODBC) SQLParamOptions 函数允许将单个 Transact-SQL 语句的多个参数集以一个批处理形式发送到服务器，从而也可减少往返次数。

可以使用 SQL 事件探查器监视、筛选和捕获所有从客户端应用程序发送到 SQL Server 的调用。它通常可以揭示因对服务器的不必要调用而导致的意外应用程序开销。SQL 事件探查器还可以显示可将当前单独发送到服务器的语句放入批处理中的机会。有关更多信息，请参见使用 SQL 事件探查器进行监视。

请参见

批处理

编写有效的事务


存储过程对应用程序性能的影响

所有设计优良的 Microsoft® SQL Server™ 2000 应用程序都应当使用存储过程。不论是否将应用程序的业务逻辑写入存储过程都应如此。甚至连没有业务逻辑组件的标准 Transact-SQL 语句，在用参数打包成存储过程后也能获得性能收益。编译进存储过程的 Transact-SQL 语句在执行时可省去大量的处理。有关更多信息，请参见存储过程。

存储过程的另一个优点是客户端执行请求使用网络的效率比将等效的 Transact-SQL 语句发送到服务器高。例如，假设应用程序需要将一个大的二进制值插入 image 数据列。为使用 INSERT 语句发送数据，该应用程序必须将该二进制值转换为字符串（其大小翻倍），然后发送到服务器。服务器再将该值转换回二进制格式以存储在 image 列中。相反，应用程序可以创建下列格式的存储过程：

CREATE PROCEDURE P(@p1 image) AS INSERT T VALUES (@p1)

当客户端应用程序请求执行过程 P 时，image 参数值将一直以二进制格式发送到服务器，从而节省处理时间并减少网络流量。

如果 SQL Server 存储过程中包含业务服务逻辑，因为业务服务逻辑将处理移动到数据，而不是将数据移动到处理，因而存储过程能提供更大的性能收益。


了解和避免阻塞

当来自应用程序的第一个连接控制锁而第二个连接需要相冲突的锁类型时，将发生阻塞。其结果是强制第二个连接等待，而在第一个连接上阻塞。不管是来自同一应用程序还是另外一台客户机上单独的应用程序，一个连接都可以阻塞另一个连接。

说明 一些需要锁保护的操作可能不明显，例如系统目录表和索引上的锁。

大多数阻塞问题的发生是因为一个进程控制锁的时间过长，导致阻塞的进程链都在其它进程上等待锁。

常见的阻塞情形包括：

  • 提交执行时间长的查询。

    长时间运行的查询会阻塞其它查询。例如，影响很多行的 DELETE 或 UPDATE 操作能获取很多锁，这些锁不论是否升级到表锁都阻塞其它查询。因此，一般不要将长时间运行的决策支持查询和联机事务处理 (OLTP) 查询混在一起。解决方案是想办法优化查询，如更改索引、将大的复杂查询分成简单的查询或在空闲时间或单独的计算机上运行查询。

    查询运行时间长并由此导致阻塞的一个原因是这些查询不适当地使用游标。游标可能是在结果集中浏览的便利方法，但使用游标可能比使用面向集合的查询慢。

  • 取消没有提交或回滚的查询。

    如果应用程序取消查询（如使用开放式数据库连接 (ODBC) sqlcancel 函数）但没有同时发出所需数目的 ROLLBACK 和 COMMIT 语句，则会发生这种情况。取消查询并不自动回滚或提交事务。取消查询后，所有在事务内获取的锁都将保留。应用程序必须提交或回滚已取消的事务，从而正确地管理事务嵌套级。

  • 应用程序没处理完所有结果。

    将查询发送到服务器后，所有应用程序必须立即完成提取所有结果行。如果应用程序没有提取所有结果行，锁可能会留在表上而阻塞其他用户。如果使用的应用程序将 Transact-SQL 语句透明地提交给服务器，则该应用程序必须提取所有结果行。如果应用程序没这样做（如果无法配置它执行此操作），则可能无法解决阻塞问题。为避免此问题，可以将这些应用程序限制在报表或决策支持数据库上。

  • 分布式客户端/服务器死锁。

    与常规死锁不同，分布式死锁无法由 Microsoft® SQL Server™ 2000 自动检测到。如果应用程序打开多个与 SQL Server 的连接并异步提交查询，则可能会发生分布式客户端/服务器死锁。

    例如，一个客户端应用程序线程有两个开放式连接。该线程异步启动事务并在第一个连接上发出查询。应用程序随后启动其它事务，在另一个连接上发出查询并等待结果。当 SQL Server 返回其中一个连接的结果时，应用程序开始处理这些结果。应用程序就这样处理结果，直到生成结果的查询被另一个连接上执行的查询阻塞而导致再没有可用的结果为止。此时第一个连接阻塞，无限期等待处理更多的结果。第二个连接没有在锁上阻塞，但仍试图将结果返回给应用程序。然而，由于应用程序阻塞而在第一个连接上等待结果，第二个连接的结果将得不到处理。

    若要避免此问题，请执行下列任一操作：

    • 对每个查询使用查询超时。

    • 对每个查询使用锁定超时。有关更多信息，请参见自定义锁超时。

    • 使用绑定连接。有关更多信息，请参见使用绑定连接。

SQL Server 本质上是受客户端应用程序操纵的傀儡。客户端应用程序对服务器上获取的锁几乎有完全的控制（并对锁负责）。虽然 SQL Server 锁管理器自动使用锁保护事务，但这受客户端应用程序发出的查询类型和对结果的处理方式的直接鼓动。因此，大多数阻塞问题的解决方案都涉及检查客户端应用程序。

阻塞问题常要求检查应用程序提交的 SQL 语句本身，以及检查与连接管理、所有结果行的处理等有关的应用程序行为本身。如果开发工具不允许显式控制连接管理、查询超时、结果处理等，阻塞问题可能得不到解决。

设计应用程序以避免阻塞的准则包括：

  • 不要使用或设计使用户得以填写编辑框的应用程序，编辑框会生成长时间运行的查询。例如，不要使用或设计提示用户输入的应用程序，允许某些字段保留空白或允许输入通配符。这可能导致应用程序提交运行时间过长的查询，从而导致阻塞问题。

  • 不要使用或设计使用户得以在事务内输入内容的应用程序。

  • 允许取消查询。

  • 使用查询或锁定超时，防止失控查询和避免分布式死锁。

  • 立即完成提取所有结果行。

  • 使事务尽可能简短。

  • 显式控制连接管理。

  • 在所预计的并发用户全负荷下对应用程序进行应力测试。

请参见

死锁

锁定


优化分布式查询

Microsoft® SQL Server™ 2000 分布式查询使用户得以通过使用 SELECT、INSERT、UPDATE 和 DELETE 语句，以引用本地表的方式引用远程表和行集。当数据源位于远程计算机上时，分布式查询可实现在整个网络内检索数据。因此，SQL Server 执行两种针对分布式查询的优化类型来改进性能：

  • 对 OLE DB SQL 命令提供程序使用远程查询执行。

  • 对 OLE DB 索引提供程序使用索引访问。

如果 OLE DB 提供程序满足下列最低要求，则将该 OLE DB 提供程序视为 SQL 命令提供程序。

  • 支持 Command 对象及其所有强制接口。

  • 支持 DBPROPVAL SQL SUBMINIMUM 语法，或在 Entry 级或更高级支持 SQL-92，或在 Core 级或更高级支持 ODBC。提供程序应通过 DBPROP_SQLSUPPORT OLE DB 属性表现此专用语级别。

如果 OLE DB 提供程序满足下列最低要求，则将该 OLE DB 提供程序视为索引提供程序：

  • 支持带 TABLES、COLUMNS 和 INDEXES 架构行集的 IDBSchemaRowset 接口。

  • 支持通过指定索引名称和相应的基表名称、使用 IOpenRowset 在索引上打开行集。

  • 索引对象应支持其所有强制接口：IRowset、IRowsetIndex、IAccessor、IColumnsInfo、IRowsetInfo 和 IConvertTypes。

  • 为了在从索引检索到的书签以外的行上定位，（使用 IOpenRowset）在索引基表上打开的行集应支持 IRowsetLocate 接口。
远程查询执行

SQL Server 试图将评估分布式查询的工作尽可能多地委派给 SQL 命令提供程序。如果 SQL 查询只访问存储在提供程序数据源中的远程表，将从原始分布式查询中析取该查询并在提供程序上执行。这将减少从提供程序返回的行数，并使提供程序得以在评估查询时使用它的索引。

在多大程度上将原始分布式查询委派给 SQL 命令提供程序的影响因素包括：

  • SQL 命令提供程序支持的专用语级别

    SQL Server 仅在受特定的专用语级别支持时才委派操作。专用语级别由高到低为：SQL Server、SQL-92 Entry 级、ODBC core 和 Jet.专用语级别越高，SQL Server 可以给提供程序委派的操作就越多。

    说明 当提供程序对应于 SQL Server 链接服务器时，使用 SQL Server 专用语级别。

    每个专用语级别都是其下属级别的超集。因此，如果将操作委派给某个级别，也就将它委派给了这一级之上的所有级别。

    始终不将涉及下列各项的查询委派给提供程序，总在本地对这类查询进行评估：

    • bit

    • uniqueidentifier

    下列操作/语法元素委派给对应的专用语级别（和所有更高的级别）：

    • SQL Server：外联接、CUBE、ROLLUP、模运算符 (%)、位运算符、字符串函数和算术系统函数。

    • SQL-92 Entry 级：UNION 和 UNION ALL。

    • ODBC 核心：带 DISTINCT 的聚合函数和字符串常量。

    • Jet：不带 DISTINCT 的聚合函数、排序 (ORDER BY)、内连接、谓词、子查询运算符（EXISTS、ALL、SOME、IN）、DISTINCT、在上级中没提到的算术运算符、在上级中没提到的常量、以及所有逻辑运算符。

    例如，除涉及 CUBE、ROLLUP、外联接、模运算符 (%)、位运算符、字符串函数和算术系统函数的操作外，将所有其它操作都委派给不同时也是 SQL Server 的 SQL-92 Entry 级提供程序。

  • 排序规则兼容性

    对于分布式查询，所有字符数据的比较语义由字符集和本地 SQL Server 的排序次序定义。Microsoft SQL Server 2000 支持多种排序规则（每一列的排序规则可以各不相同），每个字符值都具有相关联的排序规则属性。SQL Server 2000 解释来自远程数据源的字符数据的排序规则属性，并相应地对其进行处理。有关远程列的排序规则的更多信息，请参见分布式查询中的排序规则。

    SQL Server 仅在可以确定下列条件时，才能将在字符列上的比较和 ORDER BY 操作委派给提供程序：

    • 基础数据源使用列的排序规则序列和字符集。
      • 字符比较语义遵从 SQL-92（和 SQL Server）标准。
  • SQL Server 将根据"分布式查询中的排序规则"主题中的表，确定每一列的排序规则。如果远程数据源支持该排序规则，则提供程序被视为排序规则兼容。

  • 其它 SQL 支持注意事项

    SQL 专用语级别不规定下列 SQL 语法元素：

    • 嵌套查询支持

      如果提供程序支持嵌套查询（子查询），则 SQL Server 将这些操作委派给提供程序。由于不能通过 OLE DB 属性自动确定嵌套查询支持，系统管理员应设置 NestedQueries 提供程序选项以向 SQL Server 表明提供程序支持嵌套查询。

    • 参数标记支持

      如果提供程序通过在查询中使用 ? 参数标记支持参数化查询执行，则 SQL Server 可以将参数化查询执行委派给提供程序。由于不能通过 OLE DB 属性自动确定嵌套查询支持，系统管理员应设置 DynamicParameters 提供程序选项以向 SQL Server 表明提供程序支持嵌套查询。

索引访问

SQL Server 可以使用用到索引提供程序的索引的执行策略，以便评估谓词和在远程表上执行排序操作。设置 IndexAsAccessPath 提供程序选项以在提供程序上启用索引访问。

此外，使用涉及字符列的索引时，将相应链接服务器的 collation compatible 链接服务器配置选项设置为 true。有关更多信息，请参见 sp_serveroption。

说明 使用 SQL 查询分析器以图形方式显示执行计划，以便确定给定分布式查询的执行计划。在执行计划中使用远程查询执行时，使用 Remote Query 逻辑和物理运算符表示该查询执行。此运算符的参数显示远程执行的查询。

请参见

为分布式查询配置 OLE DB 提供程序

子查询基础知识


优化实用工具和工具性能

可在生产数据库上执行以获得最佳性能收益的三个操作包括：

  • 备份和还原操作。

  • 将数据大容量复制到表中。

  • 执行数据库控制台命令 (DBCC) 操作。

一般情况下，不需要优化这些操作。然而，在性能很关键的情形中，可采用一些技巧优化性能。


优化备份和还原性能

Microsoft® SQL Server™ 2000 提供几种方法提高备份及还原操作的速度：

  • 使用多个备份设备使得可以将备份并行写入所有设备。同样，可以将备份并行从多个设备还原。备份设备的速度是备份吞吐量的一个潜在瓶颈。使用多个设备可以按使用的设备数成比例提高吞吐量。有关更多信息，请参见使用多个媒体或设备。

  • 使用数据库备份、差异数据库备份和事务日志备份的组合，可以将故障恢复所需的时间减到最少。差异数据库备份可以减少必须应用于恢复数据库操作的事务日志量。这种方法通常比创建完整数据库备份快。有关更多信息，请参见有日志记录和最小日志记录的大容量复制操作.。

  • 有日志记录和最小日志记录的大容量复制操作
优化数据库、差异数据库和文件备份性能

创建数据库备份包含两个步骤：

  • 将数据从数据库文件复制到备份设备。

  • 将事务日志中用于将数据库前滚到一致状态的那部分复制到相同的备份设备。

与创建数据库备份一样，创建差异数据库备份也包括上面两步，但只复制已更改的数据（尽管需要读取所有数据库页以确定数据是否更改）。

备份数据库文件只需一步：将数据从数据库文件复制到备份设备。

用于存储数据库的数据库文件按磁盘设备排序，并给每个设备指派读取器线程。该读取器线程从数据库文件中读取数据。给每个备份设备指派写入器线程。写入器线程将数据写入备份设备。通过在更多的逻辑驱动器中分布数据库文件可以增加并行读取操作。同样，通过使用更多的备份设备可以增加并行写操作。

一般情况下，瓶颈是数据库文件或备份设备。如果读取吞吐总量比备份设备吞吐总量大，则瓶颈在备份设备这一侧。添加更多的备份设备（如果必要还添加 SCSI 控制器）可以提高性能。然而，如果备份吞吐总量比读取吞吐总量大，则应在设备上添加更多的数据库文件或者在 RAID（独立磁盘冗余阵列）设备内使用更多磁盘，以便增加读取吞吐量。

优化事务日志备份性能

创建事务日志备份只包含单个步骤：将日志中尚未备份的部分复制到备份设备。虽然可能有多个事务日志文件，但事务日志在逻辑上是某个线程按顺序读取的一个流。

给每个备份设备指派读取器/写入器线程。通过添加更多的备份设备可以获得更高的性能。

瓶颈可能是包含事务日志文件的磁盘设备或者是备份设备，具体取决于它们的相对速度和使用的备份设备数。添加更多备份设备将提高线性比例，直到达到包含事务日志文件的磁盘设备最大容量，此后如果不通过使用磁盘条带化等方法提高包含事务日志的磁盘设备的速度，将不可能获得更多性能收益。

优化还原性能

还原数据库备份或差异数据库备份包含四个步骤：

  • 创建数据库和事务日志文件，如果二者还没有存在。

  • 将数据从备份设备复制到数据库文件。

  • 从事务日志文件复制事务日志。

  • 前滚事务日志，然后（如果需要）重新启动恢复。

应用事务日志备份包含两个步骤：

  • 将数据从备份设备复制到事务日志文件。

  • 前滚事务日志。

还原数据库文件包含两个步骤：

  • 创建任何丢失的数据库文件。

  • 将数据从备份设备复制到数据库文件。

如果数据库和事务日志文件还没有存在，必须先创建它们才能将数据还原到其中。创建数据库和事务日志文件并将文件内容初始化为零。单独的工作线程并行创建和初始化文件。按磁盘设备排序数据库和事务日志文件，并给每个磁盘设备指派单独的工作线程。创建和初始化文件需要很大的吞吐量，因此在可用的逻辑驱动器中均匀分布文件能产生最佳性能。

通过读取器/写入器线程将数据和事务日志从备份设备复制到数据库和事务日志文件；给每个备份设备指派一个线程。性能受备份设备传送数据的能力或数据库和事务日志文件接收数据的能力的限制。因此，性能随添加的备份设备数线性地提高，直到达到数据库或事务日志文件接收数据能力的极限。

前滚事务日志操作的性能已经固定，除使用更快的计算机外不能进一步优化。

优化磁带备份设备性能

有四个变量影响磁带备份设备的性能，并使 SQL Server 备份及还原性能操作得以在大体上随添加更多磁带设备而提高线性比例。

  • 软件数据块大小

  • 共享小型计算机系统接口 (SCSI) 总线的磁带设备数

  • 磁带设备类型

软件数据块大小是由 SQL Server 为最佳性能计算的，不应更改。

许多高速磁带驱动器如果对每个所使用的磁带驱动器有专用 SCSI 总线，将运行得更好。本机传输速率超过 SCSI 总线速度的 50% 的驱动器必须在专用 SCSI 总线上。

有关影响磁带驱动器性能的设置的更多信息，请参见磁带驱动器供应商文档。

重要 永远不要将磁带驱动器与磁盘或 CD-ROM 驱动器放置在同一个 SCSI 总线上。对这些设备的错误处理操作互不兼容。

优化磁盘备份设备性能

磁盘备份设备的原始 I/O 速度影响磁盘备份设备性能，并使 SQL Server 备份及还原性能操作得以在大体上随添加多个磁盘设备而线性提高。

在对磁盘备份设备使用 RAID（独立磁盘冗余阵列）时需认真考虑。例如，RAID 5 的写入性能低，大致与单个磁盘的速度相同（由于必须维护奇偶信息）。另外，将数据追加到文件的原始速度明显比原始设备写入速度慢。

如果将备份设备高度条带化，以便使对备份设备的最大写入速度远远超过备份设备将数据追加到文件的速度，则在相同的条带集上放置几个逻辑备份设备会比较合适。换句话说，可以通过在相同的逻辑驱动器上放置几个备份媒体家族来提高备份性能。然而，需要采用经验方法确定这对每个环境是收益还是损失。通常情况下，最好将每个备份设备放置在单独的磁盘设备上。

一般在 SCSI 总线上只有少数几个磁盘可以最大速度运行，但 Ultra-wide 和 Ultra-2 总线可以处理更多磁盘。不过，很可能需要认真配置硬件以获得最佳性能。

有关影响磁盘性能的设置的更多信息，请参见磁盘供应商文档。

数据压缩

如今的磁带驱动器有内置的硬件数据压缩，可显著提高将数据传送到驱动器的有效传送速率。数据压缩可以提高将数据传送到磁带驱动器的有效传送速率，该速率超过通过禁用硬件压缩所达到的速率。数据库内实数据的可压缩性取决于数据本身和所使用的磁带驱动器。对于大范围的数据库，典型的数据压缩率是从 1.2:1 到 2:1。该压缩率对于在多种业务应用程序中使用的数据是典型的，但有些数据库可能有更高或更低的压缩率。例如，主要包含已压缩图像的数据库将不能再由磁带驱动器进一步压缩。有关数据压缩的更多信息，请参见磁带驱动器供应商文档。

默认情况下 SQL Server 支持硬件压缩，但可以使用 3205 跟踪标记禁用硬件压缩。在极少数情况下，禁用硬件压缩可以提高备份性能。例如，如果数据已经完全压缩，禁用硬件压缩可防止磁带驱动器浪费时间试图进一步压缩数据。

有关跟踪标记的更多信息，请参见跟踪标记。

传送到磁带的数据量

创建数据库备份只捕获数据库中包含实际数据的部分，而不备份未使用的空间。其结果将使备份操作的速度更快。

虽然可以根据需要将 SQL Server 2000 数据库配置为自动增长，但可继续保留数据库内的空间以保证该空间可用。保留数据库内的空间对备份吞吐量和备份数据库所需的总时间没有负面影响。

请参见

处理大型使命关键环境

SQL Server:Backup Device 对象

SQL Server:Databases 对象


优化大容量复制性能

为尽可能快地大容量复制数据，可使用下列选项指定如何使用 bcp 实用工具或 BULK INSERT 语句将数据大容量复制到 Microsoft® SQL Server™ 2000 内：

  • 使用有日志记录和无日志记录的大容量复制。

  • 对并行数据装载使用 bcp 实用工具。

  • 控制锁定行为。

  • 使用批处理。

  • 排序数据文件。

有关更多信息，请参见大容量复制性能考虑。

说明 如果可能，使用 BULK INSERT 语句而不是 bcp 实用工具将数据大容量复制到 SQL Server 内。BULK INSERT 语句比 bcp 实用工具快。

有两个因素决定可以或应该使用哪个选项以提高大容量复制操作性能：

  • 表内现有的数据量相对于要复制到表内的数据量。

  • 表上索引的数目和类型。

另外，这些因素还取决于是从单个客户端还是并行从多个客户端将数据大容量复制到表内。

将数据从单个客户端装载到空表内

当将数据从单个客户端装载到空表内时，建议：

  • 指定 TABLOCK 提示。这使得在大容量复制操作过程中使用表级锁。

  • 使用 ROWS_PER_BATCH 提示指定大的批处理大小。建议使用单个批处理代表整个文件的大小。

  • 指定无日志记录的大容量复制操作。不应在执行无日志记录操作之后创建事务日志备份。有关更多信息，请参见有日志记录和无日志记录的大容量复制操作。

另外，如果表有聚集索引并对数据文件内的数据排序以匹配聚集索引键列，则将数据大容量复制到已经有聚集索引键的表内并指定 ORDER 提示。这明显比在将数据复制到表内之后创建聚集索引快。

如果表上还存在非聚集索引，则在将数据复制到表内之前除去这些索引。若将数据大容量复制到没有非聚集索引的表内，然后重新创建非聚集索引，则一般比将数据大容量复制到已经有非聚集索引的表内快。

将数据从单个客户端装载到非空表内

将数据复制到已包含数据的表内时，如何执行带索引的大容量复制操作取决于表内现有的数据量相对于要复制到表内的数据量。随着要复制到表内的数据所占百分比增大（基于表内现有的数据量），除去表上的所有索引、执行大容量复制操作、然后在装载数据后重新创建索引将会更快。

作为一般准则，下表显示针对不同类型的索引建议向表内添加的数据量。如果超过下列百分比，可能会发现除去并重新创建索引变得更快。

索引 | 添加的数据量
只有聚集索引 | 30%
有聚集索引和一个非聚集索引 | 25%
有聚集索引和两个非聚集索引 | 25%
只有单个非聚集索引 | 100%
有两个非聚集索引 | 60%

从多个客户端并行装载数据

如果 SQL Server 运行在有多个处理器的计算机上，并且可以将要大容量复制到表内的数据分区成单独的数据文件，则建议从多个客户端将数据并行装载到同一个表内，从而提高大容量复制操作的性能。例如，将大容量复制从八个客户端装载到一个表里，每一个客户端必须有一个包含分区数据的部分。为获得最大性能，每个客户端的批处理大小应与客户端数据文件相同。

从多个客户端将数据复制到表内时，应考虑下列因素：

  • 必须先将表上的所有索引除去，然后在表上重新创建索引。考虑通过同时从单独的客户端创建每个辅助索引来并行重新创建辅助索引。

  • 在装载时聚集索引不存在，因此使用已排序的数据和 ORDER 提示不会影响性能。

  • 数据必须分为多个输入文件，每个客户端一个文件。

与从单个客户端的大容量复制操作一样，建议：

  • 指定 TABLOCK 提示。这使得在大容量复制操作过程中使用表级锁。

  • 使用 ROWS_PER_BATCH 提示指定大的批处理大小。建议对每个客户端，使用单个批处理代表整个客户端文件的大小。

  • 将 select into/bulkcopy 选项设置为真以启用无日志记录的操作。
在运行 SQL Server 的计算机之间复制数据

如果将数据从一台运行 SQL Server 实例的计算机复制到另一台，则使用本机格式或 Unicode 本机格式执行大容量复制操作。有关更多信息，请参见使用本机格式、字符格式和 Unicode 格式。

如果源表有聚集索引或者打算将数据大容量复制到带聚集索引的表内：

  1. 将数据从源表向外大容量复制时，指定 SELECT 语句和适当的 ORDER BY 子句以创建有序数据文件。

  2. 将数据大容量复制到 SQL Server 内时使用 ORDER 提示。有关更多信息，请参见有序数据文件。

请参见

使用 bcp 和 BULK INSERT

SQL Server:Databases 对象


优化 DBCC 性能

数据库控制台命令 (DBCC) 往往大量占用 CPU 及磁盘，因为 DBCC 必须读取每个数据页，而这需要从磁盘到内存全都检查一遍（除非数据页已高速缓存到内存中）。当系统上有许多活动（如大量的查询处理）而运行 DBCC 时，可用内存减少而且 Microsoft® SQL Server™ 2000 被迫将数据页发送到 tempdb 数据库中进行假脱机处理，DBCC 的性能由此削弱。因此，如果使更多内存可用于 DBCC 处理，将可以高速缓存数据库中的更多内容，从而使 DBCC 语句执行得更快。

tempdb 数据库驻留在磁盘上，因此在将数据写入或写出磁盘时，来自 I/O 操作的瓶颈将削弱性能。对大型数据库（相对于可用内存的大小而言）运行 DBCC 会导致送到 tempdb 数据库进行假脱机处理，与系统活动无关。因此，建议将 tempdb 数据库放置在与用户数据库分开的一个或多个快速磁盘上，如 RAID（独立磁盘冗余阵列）。有关更多信息，请参见 ALTER DATABASE 和 RAID。

说明 执行 DBCC CHECKDB 时将对数据库内的每个表自动执行 DBCC CHECKTABLE 和 DBCC CHECKALLOC，因而不必单独运行这两个语句。

请参见

DBCC

SQL Server:Databases 对象


优化服务器性能

Microsoft® SQL Server™ 2000 自动调整很多服务器配置选项，因此系统管理员只需做很少的调整（如果有）。这些配置选项可以由系统管理员修改，但一般建议保留为默认值，以使 SQL Server 能根据运行时的情况自动对自身进行调整。

不过，如果需要，可以配置下列组件以优化服务器性能：

  • SQL Server 内存

  • I/O 子系统

  • Microsoft Windows NT® 选项


使用内存配置选项优化服务器性能

Microsoft® SQL Server™ 2000 的内存管理组件消除了对 SQL Server 可用的内存进行手工管理的需要。SQL Server 在启动时根据操作系统和其它应用程序当前正在使用的内存量，动态确定应分配的内存量。当计算机和SQL Server 上的负荷更改时，分配的内存也随之更改。有关更多信息，请参见内存构架。

下列服务器配置选项可用于配置内存使用并影响服务器性能：

  • min server memory

  • max server memory

  • max worker threads

  • index create memory

  • min memory per query

min server memory 服务器配置选项可用于确保 SQL Server 至少以最小的分配内存量启动，并且内存低于该值时不会释放内存。可以基于 SQL Server 的大小及活动将该配置选项设置为特定的值。始终将 min server memory 服务器配置选项设置为某个合理的值，以确保操作系统不向 SQL Server 请求太多内存而影响 SQL Server 性能。

max server memory 服务器配置选项可用于：在 SQL Server 启动及运行时，指定 SQL Server 可以分配的最大内存量。如果知道有多个应用程序与 SQL Server 同时运行，而且想保障这些应用程序有足够的内存运行，可以将该配置选项设置为特定的值。如果这些其它应用程序（如 Web 服务器或电子邮件服务器）只根据需要请求内存，则 SQL Server 将根据需要给它们释放内存，因此不要设置 max server memory 服务器配置选项。然而，应用程序通常在启动时不假选择地使用可用内存，而如果需要更多内存也不请求。如果有这种行为方式的应用程序与 SQL Server 同时运行在相同的计算机上，则将 max server memory 服务器配置选项设置为特定的值，以保障应用程序所需的内存不由 SQL Server 分配出。

不要将 min server memory 和 max server memory 服务器配置选项设置为相同的值，这样做会使分配给 SQL Server 的内存量固定。动态内存分配可以随时间提供最佳的总体性能。有关更多信息，请参见服务器内存选项。

max worker threads 服务器配置选项可用于指定为用户连接到 SQL Server 提供支持的线程数。255 这一默认设置对一些配置可能稍微偏高，这要具体取决于并发用户数。由于每个工作线程都已分配，因此即使线程没有正在使用（因为并发连接比分配的工作线程少），可由其它操作（如高速缓冲存储器）更好地利用的内存资源也可能是未使用的。一般情况下，应将该配置值设置为并发连接数，但不能超过 1,024。有关更多信息，请参见max worker threads 选项。

说明 当 SQL Server 运行在 Microsoft Windows® 95 或 Microsoft Windows 98 上时，最大工作线程服务器配置选项不起作用。

index create memory 服务器配置选项控制创建索引时排序操作所使用的内存量。在生产系统上创建索引通常是不常执行的任务，通常调度为在非峰值时间执行的作业。因此，不常创建索引且在非峰值时间时，增加该值可提高索引创建的性能。不过，最好将 min memory per query 配置选项保持在一个较低的值，这样即使所有请求的内存都不可用，索引创建作业仍能开始。有关更多信息，请参见 index create memory 选项。

min memory per query 服务器配置选项可用于指定分配给查询执行的最小内存量。当系统内有许多查询并发执行时，增大 min memory per query 的值有助于提高消耗大量内存的查询（如大型排序和哈希操作）的性能。不过，不要将 min memory per query 服务器配置选项设置得太高，尤其是在很忙的系统上，因为查询将不得不等到能确保占有请求的最小内存、或等到超过 query wait 服务器配置选项内所指定的值。如果可用内存比执行查询所需的指定最小内存多，则只要查询能对多出的内存加以有效的利用，就可以使用多出的内存。有关更多信息，请参见 min memory per query 选项和 query wait 选项.。

请参见

监视内存的使用


使用 I/O 配置选项优化服务器性能

下列服务器配置选项可用于配置 I/O 的使用并影响服务器性能：

  • recovery interval

recovery interval 服务器配置选项控制 Microsoft® SQL Server™ 2000 在每个数据库内发出检查点的时间。默认情况下，SQL Server 确定执行检查点操作的最佳时间。然而，若要确定这是否为适当的设置，需要使用 Windows NT 性能监视器监视数据库文件上的磁盘写入活动。导致磁盘利用率达到 100% 的活动尖峰值会妨害性能。若更改该参数以使检查点进程较少出现，通常可以提高这种情况下的总体性能。但仍须继续监视性能以确定新值是否已对性能产生正面影响。有关更多信息，请参见recovery interval 选项。

请参见

监视磁盘活动


使用 Windows NT 选项优化服务器性能

可将服务器上的 Microsoft® Windows NT® 2000 选项设置成：

  • 最大化吞吐量。

  • 配置服务器任务调度。

  • 配置虚拟内存。


最大化吞吐量

SQL Server 安装程序自动配置 Microsoft® Windows NT® 以使网络应用程序的吞吐量最大。这使得服务器可以接纳更多的连接。虽然对 Microsoft SQL Server™ 2000 建议使网络应用程序的吞吐量最大，但可以更改该设置。

如果安装了全文检索功能，则必须设置 Windows NT Server 或 Windows 2000 配置以使网络应用程序的吞吐量最大，并且不能更改。

说明 Windows NT Server 配置设置对运行 Windows NT Workstation 的计算机不适用。有关更多信息，请参见 Windows NT 和 Windows 2000 文档。


配置服务器任务调度

如果打算从本地客户端（与服务器运行在同一台计算机上的客户端）连接到 Microsoft SQL Server™ 2000，可通过设置服务器以相同的优先级运行前台和后台应用程序来改进处理时间。作为在后台运行的应用程序，SQL Server 便可与在前台运行的其它应用程序具有相同的优先级。有关更多信息，请参见 Windows NT® 和 Windows 2000 文档。

说明 运行 SQL Server 安装程序时，在 Microsoft Windows NT 4.0 和 Microsoft Windows 2000（ SQL Server 的默认设置）中的 background services 中将服务器任务设置为 none，这将为前台程序和后台程序提供相等的处理器时间。可以将服务器任务设置设置设为 maximum（Microsoft Windows NT 默认值）或 applications（Microsoft Windows 2000 默认值），这将为前台应用程序提供最大的处理器时间。


配置虚拟内存

Microsoft® Windows NT® 或 Windows 2000 虚拟内存大小应基于计算机上并发运行的服务进行配置。运行 Microsoft SQL Server™ 2000 时，可考虑将虚拟内存大小设置为计算机中安装的物理内存的 1.5 倍。

如果另外安装了全文检索功能，并打算运行 Microsoft 搜索服务以便执行全文索引和查询，可考虑：

  • 将虚拟内存大小配置为至少是计算机中安装的物理内存的 3 倍。

  • 将 SQL Server max server memory 服务器配置选项配置为物理内存的 1.5 倍（虚拟内存大小设置的一半）。

如果将虚拟内存设置配置得太低，则会出现下面的 Windows NT 错误：

Your system is running low on virtual memory. Please close some applications. You can then start the System option in the Control Panel and choose the Virtual Memory button to create an additional paging file or increase the size of your current paging file.

说明 有关更多信息，请参见 Windows NT 和 Windows 2000 文档。