只有 SQL Server 可以创建和更新临时统计信息。 但是,你可以使用用于永久统计信息的相同工具来删除临时统计信息和监视统计信息属性:
使用 DROP STATISTICS 语句删除临时统计信息。
使用 sys.stats 和 sys.stats_columns 目录视图监视统计信息。 sys.stats
系统目录视图包含 is_temporary
列,用于指示哪些统计信息是永久的,哪些统计信息是临时的。
因为临时统计信息存储于 tempdb
中,所以重新启动 SQL Server 服务将导致所有临时统计信息消失。
何时更新统计信息
查询优化器确定统计信息何时可能过期,然后在查询计划需要统计信息时更新它们。 在某些情况下,将 AUTO_UPDATE_STATISTICS 设置为 ON 时,可通过更频繁地更新统计信息来优化查询计划,进而提高查询性能。 可以使用 UPDATE STATISTICS
语句或存储过程 sp_updatestats
来更新统计信息。
更新统计信息可确保查询使用最新的统计信息进行编译。 通过任何过程更新统计信息都可能会导致查询计划自动重新编译。 我们建议不要太频繁地手动更新统计信息,因为需要在改进查询计划和重新编译查询所用时间之间权衡性能。 具体的折衷方案取决于你的应用程序。
在使用 UPDATE STATISTICS
或 sp_updatestats
更新统计信息时,我们建议保持 AUTO_UPDATE_STATISTICS 设置为 ON,以便查询优化器定期更新统计信息。
要详细了解如何更新列、索引、表或索引视图的统计信息,请参阅 UPDATE STATISTICS (Transact-SQL)。
有关如何为数据库中的所有用户定义表和内部表更新统计信息的信息,请参阅存储过程 sp_updatestats (Transact-SQL)。
有关自动统计信息更新的阈值的详细信息,请参阅 AUTO_UPDATE_STATISTICS 选项。
当 AUTO_UPDATE_STATISTICS
设置为 OFF 时,计划重新编译仍可能出于其他各种原因发生,但由于统计信息更新过期,因此不会自动发生。 当 AUTO_UPDATE_STATISTICS
设置为 OFF 时,统计信息更新将仅通过其他手动计划的进程(如维护计划)进行。 将 AUTO_UPDATE_STATISTICS
设置为 OFF 可能因此导致并非最佳的查询计划以及查询性能下降。
检测过期统计信息
若要确定最近一次更新统计信息的时间,请使用 sys.dm_db_stats_properties 或 STATS_DATE 函数。
在以下情况下考虑更新统计信息:
查询执行时间很长。
在升序或降序键列上发生插入操作。
在维护操作后。
有关手动更新统计信息的示例,请参阅 UPDATE STATISTICS (Transact-SQL)。
查询执行时间很长
如果查询响应时间很长或不可预知,则在执行其他故障排除步骤前,确保查询具有最新的统计信息。
在升序或降序键列上发生插入操作
与查询优化器执行的统计信息更新相比,升序或降序键列(例如 IDENTITY 或实时时间戳列)上的统计信息可能要求更频繁地更新。 插入操作将新值追加到升序或降序键列上。 添加的行的数目可能过小,以致无法触发统计信息更新。 如果统计信息不是最新的并且查询从最频繁添加的行中选择数据,则当前统计信息将没有这些新值的基数估计。 这可能导致不精确的基数估计和查询性能低下。
例如,如果统计信息未更新以包括最近销售订单日期的基数估计,则从最近销售订单日期选择的查询将具有不精确的基数估计。
在维护操作后
考虑在执行维护过程(例如截断表或对很大百分比的行执行大容量插入)后更新统计信息。 这可以避免在将来查询等待自动统计信息更新时在查询处理中出现延迟。
索引的重新生成、碎片整理或重新组织之类的操作不会更改数据的分布。 因此,在执行 ALTER INDEX REBUILD、DBCC REINDEX、DBCC INDEXDEFRAG 或 ALTER INDEX REORGANIZE 操作后,无需更新统计信息。 查询优化器将在使用 ALTER INDEX REBUILD
或 DBCC DBREINDEX
对表或视图重新生成索引时更新统计信息,但是,此统计信息更新是重新创建索引的副产品。 在 DBCC INDEXDEFRAG
或 ALTER INDEX REORGANIZE
操作后,查询优化器并不更新统计信息。
从 SQL Server 2016 (13.x) SP1 CU4 开始,使用 CREATE STATISTICS (Transact-SQL) 或 UPDATE STATISTICS (Transact-SQL) 的 PERSIST_SAMPLE_PERCENT 选项设置和保留未显式指定采样百分比的后续统计信息更新的特定采样百分比。
自动索引和统计信息管理
使用自适应索引碎片整理等智能解决方案,自动管理一个或多个数据库的索引碎片整理和统计信息更新。 此过程根据碎片级别以及其他参数,自动选择是重新生成索引还是重新组织索引,并使用线性阈值更新统计信息。
高效使用统计信息的查询
某些查询实现(如查询谓词中的局部变量和复杂的表达式)可能导致查询计划不是最佳的。 遵循有关高效使用统计信息的查询设计指导原则可以避免这种情况。 有关查询谓词的详细信息,请参阅搜索条件 (Transact-SQL)。
你可以通过应用查询设计指导原则来改进查询计划,这些查询设计指导原则高效地使用统计信息,以便改进在查询谓词中使用的表达式、变量和函数的 基数估计 。 在查询优化器不知道表达式、变量或函数的值时,它并不知道在直方图中要查找的值,因此无法从直方图检索最佳的基数估计。 查询优化器而是为直方图中所有取样行,在每个不同值的平均行数的基础上执行基数估计。 这将导致不是最佳的基数估计并且可能影响查询性能。 有关直方图的详细信息,请参阅本页的直方图部分或 sys.dm_db_stats_histogram。
下面的指导原则描述如何编写查询以便通过改进基数估计来改进查询计划。
改进表达式的基数估计
要改进表达式的基数估计,请遵循以下指导原则:
只要可能,应简化其中含常量的表达式。 查询优化器在确定基数估计前并不对包含常量的所有函数和表达式进行求值。 例如,将表达式 ABS(-100)
简化为 100
。
如果表达式使用多个变量,则考虑为表达式创建一个计算列,然后对该计算列创建统计信息或索引。 例如,如果你为表达式 WHERE PRICE + Tax > 100
创建计算列,则查询谓词 Price + Tax
可能会具有更好的基数估计。
改进变量和函数的基数估计
要改进变量和函数的基数估计,请遵循以下指导原则:
如果查询谓词使用局部变量,则考虑重新编写查询以使用参数,而非局部变量。 在查询优化器创建查询执行计划时,局部变量的值未知。 在查询使用某一参数时,查询优化器将基数估计用于传递到存储过程的第一个实际参数值。
考虑使用标准表或临时表来保存多语句表值函数 (mstvf) 的结果。 查询优化器并不为多语句表值函数创建统计信息。 使用此方法,查询优化器可对表列创建统计信息并使用它们创建更好的查询计划。
考虑使用标准表或临时表来代替表变量。 查询优化器不会为表变量创建统计信息。 使用此方法,查询优化器可对表列创建统计信息并使用它们创建更好的查询计划。 在确定是使用临时表还是表变量时需要进行一些权衡,与临时表相比,在存储过程中使用的表变量会导致更少的存储过程的重新编译。 根据应用程序,使用临时表来代替表变量可能不会改进性能。
如果某一存储过程包含使用某一传入的参数的查询,则在查询中使用该参数值之前,应避免在该存储过程内更改该参数值。 查询的基数估计基于传入的参数值,而非更新的值。 为了避免更改参数值,你可以重新编写查询以使用两个存储过程。
例如,以下存储过程 Sales.GetRecentSales
将在 @date
为 NULL
时更改参数 @date
的值。
USE AdventureWorks2022;
IF OBJECT_ID ( 'Sales.GetRecentSales', 'P') IS NOT NULL
DROP PROCEDURE Sales.GetRecentSales;
CREATE PROCEDURE Sales.GetRecentSales (@date datetime)
AS BEGIN
IF @date IS NULL
SET @date = DATEADD(MONTH, -3, (SELECT MAX(ORDERDATE) FROM Sales.SalesOrderHeader))
SELECT * FROM Sales.SalesOrderHeader h, Sales.SalesOrderDetail d
WHERE h.SalesOrderID = d.SalesOrderID
AND h.OrderDate > @date
如果对存储过程 Sales.GetRecentSales
的首次调用为 @date
参数传递了 NULL
,则查询优化器将使用针对 @date = NULL
的基数估计编译存储过程,即使查询谓词不是使用 @date = NULL
调用的。 此基数估计可能与实际查询结果中的行数差别很大。 因此,查询优化器可能会选择非最佳查询计划。 若要避免此情况发生,你可以按如下所示将存储过程重新编写成两个过程:
USE AdventureWorks2022;
IF OBJECT_ID ( 'Sales.GetNullRecentSales', 'P') IS NOT NULL
DROP PROCEDURE Sales.GetNullRecentSales;
CREATE PROCEDURE Sales.GetNullRecentSales (@date datetime)
AS BEGIN
IF @date is NULL
SET @date = DATEADD(MONTH, -3, (SELECT MAX(ORDERDATE) FROM Sales.SalesOrderHeader))
EXEC Sales.GetNonNullRecentSales @date;
IF OBJECT_ID ( 'Sales.GetNonNullRecentSales', 'P') IS NOT NULL
DROP PROCEDURE Sales.GetNonNullRecentSales;
CREATE PROCEDURE Sales.GetNonNullRecentSales (@date datetime)
AS BEGIN
SELECT * FROM Sales.SalesOrderHeader h, Sales.SalesOrderDetail d
WHERE h.SalesOrderID = d.SalesOrderID
AND h.OrderDate > @date
使用查询提示改进基数估计
为了改进局部变量的基数估计,可以将 OPTIMIZE FOR <value>
或 OPTIMIZE FOR UNKNOWN
查询提示与 RECOMPILE
一起使用。 有关详细信息,请参阅 查询提示 (Transact-SQL)。
对于某些应用程序,每次执行查询时都重新编译查询可能会占用过多时间。 OPTIMIZE FOR
查询提示可对此给予帮助,即使不使用 RECOMPILE
选项。 例如,可以将 OPTIMIZE FOR
选项添加到存储过程 Sales.GetRecentSales
中,以便指定一个特定的日期。 以下示例将 OPTIMIZE FOR
选项添加到 Sales.GetRecentSales
过程。
USE AdventureWorks2022;
IF OBJECT_ID ( 'Sales.GetRecentSales', 'P') IS NOT NULL
DROP PROCEDURE Sales.GetRecentSales;
CREATE PROCEDURE Sales.GetRecentSales (@date datetime)
AS BEGIN
IF @date is NULL
SET @date = DATEADD(MONTH, -3, (SELECT MAX(ORDERDATE) FROM Sales.SalesOrderHeader))
SELECT * FROM Sales.SalesOrderHeader h, Sales.SalesOrderDetail d
WHERE h.SalesOrderID = d.SalesOrderID
AND h.OrderDate > @date
OPTION ( OPTIMIZE FOR ( @date = '2004-05-01 00:00:00.000'))
使用计划指南改进基数估计
对于某些应用程序,查询计划指南可能不适用,原因是你无法更改查询,或者使用 RECOMPILE
查询提示可能导致过多的重新编译。 你可以使用计划指南来指定 USE PLAN 之类的其他提示,以便在向应用程序供应商调查应用程序变化的同时,控制查询的行为。 有关计划指南的详细信息,请参阅 Plan Guides。
在 Azure SQL 数据库 中,考虑使用查询存储提示来强制计划,而不是计划指南。 有关详细信息,请参阅查询存储提示。
内存优化表的统计信息
CREATE STATISTICS (Transact-SQL)
UPDATE STATISTICS (Transact-SQL)
sp_updatestats (Transact-SQL)
DBCC SHOW_STATISTICS (Transact-SQL)
ALTER DATABASE SET 选项 (Transact-SQL)
DROP STATISTICS (Transact-SQL)
CREATE INDEX (Transact-SQL)
ALTER INDEX (Transact-SQL)
创建筛选索引
控制 SQL Server 中的 Autostat (AUTO_UPDATE_STATISTICS) 行为
STATS_DATE (Transact-SQL)
sys.dm_db_stats_properties (Transact-SQL)
sys.dm_db_stats_histogram (Transact-SQL)
sys.stats
sys.stats_columns (Transact-SQL)
Microsoft SQL Server Tiger 团队工具箱中的自适应索引碎片整理
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:https://aka.ms/ContentUserFeedback。
提交和查看相关反馈