sql-server – 重新索引更新统计信息吗?

过去一周我一直在做MS10775A课程,而且培训师无法可靠回答的一个问题是:

Does a re-index update the statistics?

我们在网上发现了讨论,认为它确实存在,而事实并非如此.

解决方法

在关注更新统计数据时,您可以牢记以下几点(从 Rebuilding Indexes vs. Updating Statistics (Benjamin Nevarez)复制)

>认情况下,UPDATE STATISTICS语句仅使用表的记录样本.使用UPDATE STATISTICS WITH FULLSCAN将扫描整个表.
>认情况下,UPDATE STATISTICS语句更新索引和列统计信息.使用COLUMNS选项将仅更新列统计信息.使用INDEX选项将仅更新索引统计信息.
>重建索引,例如使用ALTER INDEX … REBUILD也将使用WITH FULLSCAN更新索引统计信息,除非the table is partitioned,in which case the statistics are only sampled(适用于sql Server 2012及更高版本).
>使用CREATE STATISTICS手动创建的统计信息不会被任何ALTER INDEX … REBUILD操作更新,包括ALTER TABLE … REBUILD. ALTER TABLE …如果正在重建的表上定义了聚簇索引,则REBUILD会更新聚簇索引的统计信息.
>重新组织索引,例如使用ALTER INDEX … REORGANIZE不会更新任何统计信息.

简短的回答是,您需要使用UPDATE STATISTICS来更新列统计信息,并且索引重建将仅更新索引统计信息.您可以使用UPDATE STATISTICS(tablename)WITH FULLSCAN强制更新表上的所有统计信息,包括index-stats和手动创建的统计信息;句法.

以下代码说明了上面封装的规则:

首先,我们将创建一个包含两列和一个聚簇索引的表:

USE tempdb;

IF OBJECT_ID(N'dbo.soMetable',N'U') IS NOT NULL
DROP TABLE dbo.soMetable;

CREATE TABLE dbo.soMetable
(
    rn int NOT NULL IDENTITY(1,1)
        CONSTRAINT pk
        PRIMARY KEY NONCLUSTERED,i int NOT NULL INDEX i,d sysname NOT NULL
) ON [PRIMARY] WITH (DATA_COMPRESSION = NONE);

CREATE UNIQUE CLUSTERED INDEX cx ON dbo.soMetable (i,d);

CREATE STATISTICS d ON dbo.soMetable (d) WITH FULLSCAN;

INSERT INTO dbo.soMetable (d,i)
SELECT c1.name,c1.id
FROM sys.syscolumns c1;

查询显示上次更新每个统计信息对象的日期:

SELECT ObjectName = sc.name + N'.' + o.name,StatsName = s.name,StatsDate = STATS_DATE(s.object_id,s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SoMetable';

结果显示尚未进行更新,这是正确的,因为我们刚刚创建了表:

╔═══════════════╦═══════════╦═══════════╗
║  ObjectName   ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═══════════╣
║ dbo.soMetable ║ cx        ║ NULL      ║
║ dbo.soMetable ║ i         ║ NULL      ║
║ dbo.soMetable ║ pk        ║ NULL      ║
║ dbo.soMetable ║ d         ║ NULL      ║
╚═══════════════╩═══════════╩═══════════╝

让我们重建整个表,看看是否更新了统计信息:

ALTER TABLE dbo.soMetable REBUILD;

SELECT ObjectName = sc.name + N'.' + o.name,s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SoMetable';
╔═══════════════╦═══════════╦═════════════════════════╗
║  ObjectName   ║ StatsName ║        StatsDate        ║
╠═══════════════╬═══════════╬═════════════════════════╣
║ dbo.soMetable ║ cx        ║ 2018-09-17 14:09:13.590 ║
║ dbo.soMetable ║ i         ║ NULL                    ║
║ dbo.soMetable ║ pk        ║ NULL                    ║
║ dbo.soMetable ║ d         ║ NULL                    ║
╚═══════════════╩═══════════╩═════════════════════════╝

结果显示只更新了聚簇索引统计信息.

接下来,我们执行一个离散的UPDATE STATS操作:

UPDATE STATISTICS dbo.soMetable(d) WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name,s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SoMetable';

如您所见,我们刚刚更新了d列的统计信息:

╔═══════════════╦═══════════╦═════════════════════════╗
║  ObjectName   ║ StatsName ║        StatsDate        ║
╠═══════════════╬═══════════╬═════════════════════════╣
║ dbo.soMetable ║ cx        ║ 2018-09-17 14:09:13.590 ║
║ dbo.soMetable ║ i         ║ NULL                    ║
║ dbo.soMetable ║ pk        ║ NULL                    ║
║ dbo.soMetable ║ d         ║ 2018-09-17 14:09:13.597 ║
╚═══════════════╩═══════════╩═════════════════════════╝

现在,我们将更新整个表格的统计信息:

UPDATE STATISTICS dbo.soMetable WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name,s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SoMetable';
╔═══════════════╦═══════════╦═════════════════════════╗
║  ObjectName   ║ StatsName ║        StatsDate        ║
╠═══════════════╬═══════════╬═════════════════════════╣
║ dbo.soMetable ║ cx        ║ 2018-09-17 14:09:13.600 ║
║ dbo.soMetable ║ i         ║ 2018-09-17 14:09:13.600 ║
║ dbo.soMetable ║ pk        ║ 2018-09-17 14:09:13.603 ║
║ dbo.soMetable ║ d         ║ 2018-09-17 14:09:13.607 ║
╚═══════════════╩═══════════╩═════════════════════════╝

如您所见,确保更新所有统计信息的唯一方法是手动更新每个统计信息,或使用UPDATE STATISTICS(table);更新整个表.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...