Lubor Kollar
Microsoft Corporation

目录

Microsoft SQL Server 2000 中查询优化器使用的统计
SQL Server 2000 中的统计数据
SQL Server 2000 收集的统计信息
   关于 INDEX ''PK_Order_Details'' 的统计信息
用 SQL Server 2000 创建统计
在 SQL Server 2000 中维护统计
统计和索引视图
总结

摘要:本文说明了收集的数据类型、数据的存储位置以及用于创建、更新与删除统计的命令。这些统计信息与存储在 Microsoft SQL Server 2000 数据库中的索引和列数据相关,SQL Server 查询优化器用它们来选择用于检索数据和执行 INSERT、SELECT、DELETE 或 UPDATE 查询的最有效方案。本文同时也概括介绍了如何在不同的级别(索引、表和数据库)上更改 SQL Server 创建与维护统计的默认设置。

Microsoft SQL Server 2000 中查询优化器使用的统计

Microsoft® SQL Server™ 2000 收集关于存储在数据库中的索引和列数据的统计信息。SQL Server 查询优化器使用这些统计信息来选择用于执行 INSERT、SELECT、DELETE 或 UPDATE 查询的最有效方案。本文说明了收集的数据类型、数据的存储位置以及用于创建、更新与删除统计的命令。默认情况下,SQL Server 2000 会自动创建和更新统计(当此类操作有用时)。本文也概括介绍了如何在不同的级别(索引、表和数据库)上更改这些默认值。

SQL Server 2000 中的统计数据

SQL Server 2000 既收集关于单个列的统计信息(单列统计),也收集关于成组的列的统计信息(多列统计)。关于一个统计对象的所有信息存储在 SYSINDEXES 表中一行的多个列中。计算列以及数据类型为 ntexttextimage

SQL Server 2000 收集的统计信息

  • 上次收集统计信息的时间(在 STATBLOB 中)。
  • 表或索引中的行数(SYSINDEXES 中的 rows 列)。
  • 表或索引所占用的页数(SYSINDEXES 中的 dpages 列)。
  • 用于生成直方图和密度信息的行数(在 STATBLOB 中,将在下面讲解)。
  • 平均键长(在 STATBLOB 中)。
  • 单列直方图,包括步数(在 STATBLOB 中)。

注意:直方图是给定列的最多 200 个值的集合。给定列中的所有值(如果通过抽样来收集统计信息,则为选定的值)会被排序;排序后序列最多会划分为 199 个间隔,以便得到最有效的统计。一般,这些间距的大小并不相等。以下数值与直方图的每个步长存储在一起。

表 1:直方图的值

RANGE_HI_KEY

键值

EQ_ROWS

指定与 RANGE_HI_KEY 精确相等的行数。

RANGE_ROWS

指定区间中的行数。(这些行小于这个 RANGE_HI_KEY,但大于上一个较小的区间键值)。

DENSITY

指定 1/n,其中 n 表示区间中互不相同的值的数目。


使用 dbcc show_statistics

表 2:用两个导出值显示 dbcc show_statistics 的直方图

DISTINCT_RANGE_ROWS

指定此区间中互不相同的行的数目(不算 RANGE_HI_KEY 值本身);DISTINCT_RANGE_ROWS = 1 / DENSITY。

AVG_RANGE_ROWS

区间中每个特定值的平均行数;AVG_RANGE_ROWS = DENSITY * RANGE_ROWS。


SQL Server 2000 中的直方图只用于单个列、多列统计中的第一列或者索引。

SQL Server 2000 按照三个步骤从排序后的列值集合生成直方图。第一步,最多收集 200 个 RANGE_HI_KEY、EQ_ROWS、RANGE_ROWS 和 DISTINC_RANGE_ROWS 的值。第二步,对每个其他的列值进行处理:该值或者被添加到上一个区间中(对值进行排序),或者创建一个新区间。如果是创建一个新区间,则两个现有的相邻区间会合并到一个区间中。SQL Server 2000 通过密度信息来选择要合并的区间,使密度最接近的两个相邻区间被合并,从而将信息的损失降到最低程度。第三步,合并更多的密度接近的区间。因此,即使列中的唯一值个数超过 200,直方图的步数也可能会小于 200。

如果通过抽样来生成直方图,那么 RANGE_ROWS、EQ_ROWS、DISTINCT_RANGE_ROWS 和 AVG_RANGE_ROWS 的值将为估计值,因此它们不必都是整数。

密度是关于给定列或列的组合中重复项数目的信息,其计算公式为 1/(互不相同的值的数目)。如果在相等条件判断表达式中使用了某个列,则会使用从直方图导出的密度来估算符合条件的行数。直方图通常用于估算不等条件判断表达式。

注意:dbcc show_statistics

一个列集合的多列统计包括以下信息:统计定义中第一个列的直方图,第一个列的密度值,以及每个列的前缀组合(单独包括第一个列)的密度值。每个统计集(一个直方图加上两个或多个密度值)都存储在 SYSINDEXES 表的一行中,同一行中还包括上次更新统计的时间戳、用于生成统计信息的抽样行数、直方图的步数和平均键数。SQL Server 2000 只为编号为 0 或 1 的索引(堆索引或群集索引)维护行数的值(rowcnt 列),并在表中的所有索引中复制该值。同样,SQL Server 2000 也为每个表和索引维护 dpages。如果收集统计信息时表中没有任何行,则该表的统计信息为空。

使用 sp_helpindexsp_helpstats 可以显示给定表中所有可用统计的列表,sp_helpindex 列出了表中的所有索引,而 sp_helpstats 则列出了表中的所有统计。每个索引都带有其中列的统计信息。在相同的列中,使用 CREATE STATISTICS 命令创建的统计信息与使用 CREATE INDEX 命令生成的统计信息等价。唯一的差别在于,CREATE STATISTICS 命令默认采用抽样方式,而 CREATE INDEX 命令则由于必须处理索引的所有行,因而使用 fullscan

下面是罗斯文数据库中 Order Details 表的所有索引和统计的示例。因为最初无索引的列上没有任何统计信息,所以在连接到罗斯文数据库后,请先运行 sp_createstats

表 3:罗斯文数据库中的 Order Details 表

sp_helpindex

index_name

index_description

index_keys

OrderID

PRIMARY 上的非群集索引

OrderID

PK_Order_Details

PRIMARY 上群集的唯一主键

OrderID、ProductID

ProductID

PRIMARY 上的非群集索引

ProductID


sp_helpstats

statistics_name

statistics_keys

Discount

Discount

Quantity

Quantity

UnitPrice

UnitPrice


也可以象下面这样使用 dbcc show_statistics 命令来显示统计信息:

dbcc show_statistics ([Order Details],PK_Order_Details)

如果没有返回任何信息,则表明上次已经更新了统计,或在表中没有任何行时就创建了索引。要更新 Order Details 表的统计,请运行 UPDATE STATISTICS [Order Details];要更新罗斯文数据库中所有表的统计,请运行 sp_updatestats

注意:   该命令的输出已经增强了可读性。

关于 INDEX ''PK_Order_Details'' 的统计信息

表 4:关于 INDEX ''PK_Order_Details'' 的统计信息

更新时间

行数

抽样的行数

步数

密度

平均
键长

2000 年 5 月 17 日下午 10:38

2155

2155

192

1.1090337E-3

8.0


所有密度

平均长度

1.2048193E-3

4.0

OrderID

4.6403712E-4

8.0

OrderID、Product ID


RANGE
_HI_KEY

RANGE_ROWS

EQ_ROWS

DISTINCT_RANGE
_ROWS

AVG_RANGE
_ROWS

10248

0.0

3.0

0

0.0

10253

11.0

3.0

4

2.75

10256

7.0

2.0

2

3.5

10260

8.0

4.0

2

2.6666667

10263

5.0

4.0

2

2.5

10267

5.0

3.0

3

1.6666666

10273

10.0

5.0

5

2.0

10278

8.0

4.0

4

2.0

10283

9.0

4.0

4

2.25

10286

7.0

2.0

2

3.5

10290

7.0

4.0

3

2.3333333

10294

8.0

5.0

2

2.6666667

10298

6.0

4.0

3

2.0

10303

9.0

3.0

4

2.25

10306

6.0

3.0

2

3.0

10309

4.0

5.0

2

2.0

10312

4.0

4.0

2

2.0

10319

11.0

3.0

5

1.8333334

10325

11.0

5.0

4

2.2

10329

10.0

4.0

3

3.3333333

10333

6.0

3.0

3

2.0

10337

7.0

5.0

3

2.3333333

10342

10.0

4.0

4

2.5

10347

10.0

4.0

4

2.5

10351

5.0

4.0

3

1.6666666

10357

11.0

3.0

4

2.2

10360

6.0

5.0

2

3.0

10363

5.0

3.0

2

2.5

10368

9.0

4.0

4

2.25

10372

6.0

4.0

3

2.0

10375

4.0

2.0

2

2.0

10380

7.0

4.0

4

1.75

10384

9.0

2.0

3

3.0

10387

5.0

4.0

2

2.5

10390

7.0

4.0

2

3.5

10393

2.0

5.0

2

1.0

10396

5.0

3.0

2

2.5

10401

11.0

4.0

4

2.75

10405

7.0

1.0

3

2.3333333

10408

8.0

3.0

2

4.0

10412

7.0

1.0

3

2.3333333

10417

10.0

4.0

4

2.5

10420

6.0

4.0

2

3.0

10424

7.0

3.0

3

2.3333333

10429

6.0

2.0

4

1.5

10432

7.0

2.0

2

3.5

10437

10.0

1.0

4

2.5

10440

7.0

4.0

2

3.5

10444

6.0

4.0

3

2.0

10446

2.0

4.0

1

2.0

10451

10.0

4.0

4

2.5

10455

7.0

4.0

3

2.3333333

10458

3.0

5.0

2

1.5

10461

5.0

3.0

2

2.5

10465

8.0

5.0

2

2.6666667

10470

9.0

3.0

4

2.25

10474

6.0

4.0

3

2.0

10479

9.0

4.0

4

2.25

10485

10.0

4.0

5

2.0

10490

10.0

3.0

4

2.5

10494

7.0

1.0

3

2.3333333

10498

7.0

3.0

3

2.3333333

10504

10.0

4.0

5

2.0

10507

3.0

2.0

2

1.5

10512

8.0

4.0

4

2.0

10515

8.0

5.0

2

4.0

10519

9.0

3.0

3

3.0

10522

5.0

4.0

2

2.5

10524

4.0

4.0

1

4.0

10528

7.0

3.0

3

2.3333333

10530

3.0

4.0

1

3.0

10535

9.0

4.0

4

2.25

10537

4.0

5.0

1

4.0

10541

10.0

4.0

3

3.3333333

10546

7.0

3.0

4

1.75

10550

7.0

4.0

3

2.3333333

10553

5.0

5.0

2

2.5

10555

4.0

5.0

1

4.0

10558

3.0

5.0

2

1.5

10564

10.0

3.0

5

2.0

10568

8.0

1.0

2

2.6666667

10572

6.0

4.0

3

2.0

10575

7.0

4.0

2

3.5

10577

3.0

3.0

1

3.0

10583

10.0

3.0

5

2.0

10587

3.0

3.0

3

1.0

10592

8.0

2.0

4

2.0

10596

8.0

3.0

2

2.6666667

10605

15.0

4.0

8

1.875

10607

3.0

5.0

1

3.0

10612

8.0

5.0

4

2.0

10616

6.0

4.0

3

2.0

10621

8.0

4.0

4

2.0

10623

2.0

5.0

1

2.0

10626

6.0

3.0

2

3.0

10634

14.0

4.0

7

2.0

10639

11.0

1.0

4

2.75

10643

6.0

3.0

3

2.0

10646

5.0

4.0

2

2.5

10650

6.0

3.0

3

2.0

10654

6.0

3.0

3

2.0

10657

4.0

6.0

2

2.0

10663

11.0

3.0

4

2.2

10666

6.0

2.0

2

3.0

10670

6.0

5.0

3

2.0

10674

8.0

1.0

2

2.6666667

10677

6.0

2.0

2

3.0

10680

5.0

3.0

2

2.5

10683

6.0

1.0

2

3.0

10686

6.0

2.0

2

3.0

10691

9.0

5.0

4

2.25

10696

11.0

2.0

4

2.75

10698

4.0

5.0

1

4.0

10709

26.0

3.0

10

2.5999999

10714

11.0

5.0

4

2.75

10722

18.0

4.0

7

2.5714285

10733

24.0

3.0

9

2.4000001

10740

12.0

4.0

6

2.0

10745

6.0

4.0

4

1.5

10747

4.0

4.0

1

4.0

10751

9.0

4.0

3

3.0

10756

9.0

4.0

4

2.25

10759

7.0

1.0

2

3.5

10762

5.0

4.0

2

2.5

10766

6.0

3.0

3

2.0

10769

5.0

4.0

2

2.5

10776

11.0

4.0

5

1.8333334

10781

6.0

3.0

4

1.5

10789

15.0

4.0

7

2.1428571

10793

7.0

2.0

3

2.3333333

10796

4.0

4.0

2

2.0

10800

6.0

3.0

3

2.0

10803

6.0

3.0

2

3.0

10806

5.0

3.0

2

2.5

10811

7.0

3.0

4

1.75

10814

5.0

4.0

2

2.5

10818

7.0

2.0

3

2.3333333

10823

7.0

4.0

4

1.75

10829

10.0

4.0

5

2.0

10832

8.0

4.0

2

4.0

10836

7.0

5.0

3

2.3333333

10839

7.0

2.0

2

3.5

10842

6.0

4.0

2

3.0

10846

7.0

3.0

3

2.3333333

10848

6.0

2.0

1

6.0

10851

5.0

4.0

2

2.5

10855

6.0

4.0

3

2.0

10858

5.0

3.0

2

2.5

10861

5.0

5.0

2

2.5

10866

8.0

3.0

4

2.0

10869

4.0

4.0

2

2.0

10872

5.0

4.0

2

2.5

10878

10.0

1.0

5

2.0

10882

7.0

3.0

3

2.3333333

10885

4.0

4.0

2

2.0

10890

8.0

3.0

4

2.0

10894

7.0

3.0

3

2.3333333

10903

15.0

3.0

8

1.875

10909

7.0

3.0

5

1.4

10912

6.0

2.0

2

3.0

10917

10.0

2.0

4

2.5

10923

10.0

3.0

5

2.0

10926

5.0

4.0

2

2.5

10930

8.0

4.0

2

2.6666667

10934

8.0

1.0

2

2.6666667

10946

27.0

3.0

10

2.4545455

10949

4.0

4.0

2

2.0

10954

8.0

4.0

4

2.0

10959

10.0

1.0

4

2.5

10962

4.0

5.0

2

2.0

10968

10.0

3.0

5

2.0

10973

5.0

3.0

4

1.25

10977

4.0

4.0

2

1.3333334

10980

10.0

1.0

2

5.0

10986

11.0

4.0

4

2.2

10990

8.0

4.0

2

2.6666667

10997

10.0

3.0

6

1.6666666

11001

10.0

4.0

3

3.3333333

11011

24.0

2.0

8

2.6666667

11014

7.0

1.0

2

3.5

11019

10.0

2.0

4

2.5

11024

10.0

4.0

4

2.5

11030

10.0

4.0

5

2.0

11034

10.0

3.0

3

3.3333333

11039

10.0

4.0

4

2.5

11053

21.0

3.0

13

1.6153846

11058

10.0

3.0

4

2.5

11064

11.0

5.0

4

2.2

11070

10.0

4.0

5

2.0

11075

9.0

3.0

4

2.25

11076

0.0

3.0

0

0.0

11077

0.0

25.0

0

0.0

(共影响 192 行)


请注意,当 sp_helpindex 输出只显示城市统计 (City) 的一个列时,show_statistics 的输出也会显示 City,Customer_id 列组合的所有密度值。这是因为表中 Customer_id

使用 SQL Server 2000 创建统计

SQL Server 2000 中有两种基本语句会生成上述统计信息:CREATE INDEX 首先会生成声明的索引,然后,作为副产品,它会为组成索引的列组合创建一个统计集;CREATE STATISTICS 只为给定列或列的组合生成统计。

另外,还有多种方法可以创建统计或索引,但归根结底,每种方法都会发出上述两个命令之一。

  • 使用 sp_createstats 为当前数据库中所有用户表的全部合格列(不包括图像和文本数据)创建统计。如果某个列已经有了直方图,则不会为其创建新的直方图。
  • 使用 dbcc dbreindex 为指定数据库中的表重新生成一个或多个索引。
  • 在查询分析器中,键入一个查询,选择“显示执行计划”(Show Execution Plan),然后执行查询。在显示的任意图标上单击右键,并选择“管理索引” (Manage Index)或“创建/更新统计信息”(Create/Update Statistics)。
  • 使用 Create Index

下面是对 pubs..authors

CREATE STATISTICS s1 ON authors (state, au_lname) WITH SAMPLE 50 PERCENT

通常,按默认抽样方式生成的统计最为理想。但有时,使用更大的样本大小来生成统计(理想状况下可以使用 fullscan)有助于查询优化,例如给定列中的值分布不均匀时(某些值频繁出现,而其他值较少出现)。使用较大的样本大小来生成统计,必须以创建统计时所需时间的延长为代价。

上面的命令创建一个两列统计。在本例中,因为表太小,所以会忽略 SAMPLE 50 PERCENT 并执行完全扫描。抽样主要用于避免过多扫描数据,并且只影响具有 1024 或更多页面 (8 MB) 的表和索引。

在 SQL Server 2000 中,创建索引的同时会为所有索引创建统计。SQL Server 在编译查询时自动创建单列统计。这些统计是为优化器必须估算密度或分发的列而创建的。这一规则有两种例外情况:首先,当直接对表执行操作所需的代价小于创建统计所需的代价时,不能为该表创建统计;其次,当服务器过于繁忙(有大量正在进行的重要操作)时,也不能创建统计。

为避免长时间维护未使用过的统计,SQL Server 2000 会记录那些自动创建的统计(仅包括那些不是创建索引的副产品的统计信息)的使用时间。几次自动更新之后,列统计会被放弃而不是被更新。如果将来需要,可以重新创建这些统计。更新统计与创建统计在代价方面并没有实质性的差别。记录使用时间的操作也不会影响用户创建的统计。

通过执行 sp_dboption dbname, 'auto create statistics', 'OFF' 可以在数据库级禁用自动创建统计的功能。

默认情况下,统计是在执行 CREATE STATISTICS 命令或自动创建统计时,通过对数据集进行抽样而创建的。CREATE INDEX 总是会扫描整个数据集,因此最初创建的索引统计并不进行抽样。CREATE STATISTICS 命令允许您通过在 WITH 子句中指定 FULLSCAN 或要扫描的数据百分比来设置样本大小。后者被认为是一个近似值。在 UPDATE STATISTICS 命令上指定 WITH RESAMPLE 时也可以继承上一个样本大小。当既存在索引(通过 fullscan 统计方式创建),其他列(通过 sample 统计方式创建)上又有统计时,该方法尤其有用。随后在 UPDATE STATISTICS 上使用 RESAMPLE 选项,将保持索引的 fullscan 统计和其他列的 sample

dbcc show_statistics

SQL Server 查询分析器也会监视自动创建统计的操作。AutoStats 事件位于 Object 跟踪事件组中。定义该跟踪时,也会选择 Integer Data、Success 和 Object ID 列。一旦捕获 AutoStats 事件,Integer Data 列将包含为给定表更新的统计数,Object ID 成为该表的 ID,而 TextData 列(默认情况下包含在跟踪定义中)则包括列的名称以及 Updated:Created: 两个前缀之一。Success 列包含潜在的 Failure 指示信息。在某些情况下,您可能会发现 AutoStats 事件不带有任何创建或更新的统计。当 auto update statistics

DROP STATISTICS 命令用于放弃统计,但不能放弃创建索引时附带生成的统计。只有将索引放弃后,才能删除其附带生成的统计。

在 SQL Server 2000 中维护统计

在表中执行了一系列 INSERT、DELETE 和/或 UPDATE 查询后,统计可能不反映给定列或索引中数据分布的真实情况。如果某个表在上次创建或更新统计之后进行了大量的更新活动,那么当 SQL Server 查询优化器需要该表中某个特定列的统计时,SQL Server 会(使用 auto update statistics)通过对列中的值进行抽样来自动更新统计。统计的自动更新由查询优化操作触发,并且只涉及查询中所引用列的一个子集。SYSINDEXES 值中的 rowmodctr 列显示了自上次创建或更新统计之后对表执行的更改次数。对于每个索引和统计集,SYSINDEXES 中都会有一个对应的行(如果表中没有群集的索引,则会有一个与堆相对应的行),SQL Server 2000 将分别维护每个索引和统计的更改次数(但在 SQL Server 7.0 中并非这样)。在表中执行 INSERT、UPDATE 和 DELETE 查询时,只会为 ID 为 0 或 1 的索引(一般,每个表中只有一个)递增 rowmodctr 值。对于其他的统计和索引,它只显示一个必须加到索引 0 或 1 的 rowmodctr

这一逻辑使得在 INSERT、UPDATE 和 DELETE 查询过程中,对每个表只需要维护一行中的 rowmodctr;同时,又能够分别跟踪每个索引中已变更的行。因此,当 auto update statistics

查询示例

在表 t1 中插入 506 行,然后创建非群集的索引 i1 和 i2。进行了这些操作之后,SYSINDEXES 表中会出现有趣的条目:

Name

Indid

rowcnt

rowmodctr

t1

0

506

506

i1

2

506

-506

i2

3

506

-506


插入了另外 213 行后,计数为:

Name

Indid

rowcnt

rowmodctr

t1

0

719

719

i1

2

506

-506

i2

3

506

-506


使用 UPDATE STATISTICS t1 (i1) 刷新了索引 i1 的统计之后:

Name

Indid

rowcnt

rowmodctr

t1

0

719

0

i1

2

506

0

i2

3

506

213


可以在不同的级别上将上面所说的 auto update statistics

  • 在数据库级别使用 sp_dboption dbname, 'auto create statistics', 'OFF'。也可以使用该 sp 来显示特定数据库的当前设置。
  • 对表、索引或统计使用 UPDATE STATISTICS 命令的 NORECOMPUTE 选项。
  • 对表或统计使用 CREATE STATISTICS 命令的 NORECOMPUTE 选项。
  • sp_autostats

也可以使用 sp_dboption、UPDATE STATISTICS 或 sp_autostats

SQL Server 2000 在每个数据库、每个索引和表的级别上分别保存自动更新统计的设置。尽管您可以使用一条 CREATE STATISTICS 命令来打开一个表中的所有统计,但必须通过更改给定表中所有统计和索引的设置来完成该操作。表 6 显示了不同的数据库、表和索引设置的组合效果。

表 6:不同的数据库、表和索引设置的组合效果

数据库设置

表/索引设置

Statistics Auto Update
对该对象是否有效

ON

ON

ON

ON

OFF

OFF

OFF

ON

OFF

OFF

OFF

OFF


自动更新统计一般通过对索引或表抽样来执行。您可以通过手动运行 CREATE 和 UPDATE 统计来改变样本大小。在这样创建统计时,统计更新会被相同的 SQL 分析器事件替代。

统计和索引的视图

通常,索引的视图上不需要统计,这是因为:只有在将基础表和索引的所有统计都附加到查询操作之后,才会考虑替换查询操作中的索引视图。但是,有一点例外:如果使用 NOEXPAND 提示在 FROM 子句中直接引用视图,就会使用统计。如果在不包含索引的视图上使用 NOEXPAND 提示,则会生成错误并无法执行操作。

因为索引视图上的统计的用途非常有限,所以不使用 sp_createstats 在索引的视图上创建索引,也不使用 sp_updatestats 对其进行更新。auto updateauto create statistics

总结

对于查询优化器,数据库中的数据统计是重要的输入。默认情况下,SQL Server 自动创建和维护统计,而不需要用户的参与。大多数 SQL Server 用户不必更改默认值,就可以获得最佳性能。SQL Server 提供了多个接口,用于更改默认的统计创建和维护的规则,但只有在默认规则不能达到最佳性能的特殊环境下,您才需要使用这些接口。