ANALYZE

最近更新时间:2019-04-22 11:12:10

收集有关一个数据库的统计信息。

概要

ANALYZE [VERBOSE] [ROOTPARTITION [ALL] ] 
   [table [ (column [, ...] ) ]]

描述

ANALYZE收集一个数据库中的表的内容的统计信息,并且将结果存储在 pg_statistic 系统目录中。接下来,查询规划器会使用这些统计信息来帮助确定查询最有效的执行计划。

如果不带参数,ANALYZE会检查当前数据库中的所有表。用户可以指定表名来收集单个表的统计信息。用户可以指定一组列名称,在这种情况下,仅收集这些列的统计信息。

ANALYZE不收集外部表上的统计信息。

重要:如果用户想要在启用GPORCA(默认启用)时在分区表上执行查询,那么用户必须在分区表的根分区上用ANALYZE ROOTPARTITION命令收集统计信息。有关GPORCA的信息,请参见“数据库管理员指南”中的“查询数据”。

注意:

用户还可以使用的数据库工具analyzedb更新表统计信息。analyzedb工具可以并发地为多个表更新统计信息。该工具还能检查表、统计信息并且只在统计信息不是当前最新或者不存在时更新之。有关该工具的信息,请参见“数据库工具指南”。

参数

ROOTPARTITION [ALL]
只在分区表的根分区上根据分区表中的数据收集统计信息。不会在叶子子分区上收集统计信息,其中的数据只会被采样。当用户指定ROOTPARTITION时,必须指定ALL或者一个分区表的名称。

如果用户在ROOTPARTITION中指定ALL,数据库会为该数据库中所有分区表的根分区收集统计信息。如果在数据库中没有分区表,会返回一个消息说明没有分区表。对于非分区表不会收集统计信息。

如果用户在ROOTPARTITION中指定一个表名并且该表不是分区表,则不会为该表收集统计信息并且会返回一个警告消息。

ROOTPARTITION子句对VACUUM ANALYZE不合法。命令VACUUM ANALYZE ROOTPARTITION会返回一个错误。

运行ANALYZE ROOTPARTITION所需的时间类似于分析一个有着相同数据的非分区表所需的时间,因为ANALYZE ROOTPARTITION仅采样叶子子分区数据。

对于分区表sales_curr_yr,这个命令例子只在分区表的根分区上收集统计信息。

ANALYZE ROOTPARTITION sales_curr_yr
这个ANALYZE命令的例子在数据库中所有分区表的根分区上收集统计信息。

ANALYZE ROOTPARTITION ALL;

VERBOSE
启用进度消息的显示。被指定时,ANALYZE会发出这些信息。

  • The table that is being processed.
  • The query that is executed to generate the sample table.
  • The column for which statistics is being computed.
  • The queries that are issued to collect the different statistics for a single column.
  • The statistics that are generated.

table
要分析的特定表的名称(可能被方案限定)。默认为当前数据库中的所有表。

column
要分析的特定列的名称。默认为所有列。

注解

定期运行ANALYZE是个好主意,或者只在表内容发生大量变化时才运行。准确的统计信息会帮助数据库选择最合适的查询计划,并且因此改进查询处理的速度。一种常用的策略是每天在系统负载低的时候运行一次VACUUM和ANALYZE。

ANALYZE要求目标表上的SHARE UPDATE EXCLUSIVE锁。这个锁会与这些锁冲突:SHARE UPDATE EXCLUSIVE、 SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE、 ACCESS EXCLUSIVE。

对于分区表,指定要分析该表的哪一部分,如果分区表有大量已经分析过的分区并且只有少数叶子子表改变,根分区或者子分区(叶子子表)会很有用。

  • 当用户在根分区表上运行ANALYZE时,会为所有的叶子子表(数据库为分区表创建的子表层次中最底层的表)收集统计信息。
  • 当用户在一个叶子子表上运行ANALYZE时,只会为该叶子子表收集统计信息。当用户在非叶子子表的子表上运行ANALYZE时,不会有统计信息被收集。

例如,用户可以创建一个分区从2006年到2016年的分区表,每年中的每个月是一个子分区。如果用户在2013年的子表上运行ANALYZE,则不会有统计信息被收集。如果用户在2013年三月的叶子子表上运行ANALYZE,则只会为该叶子子表收集统计信息。

注意:

当用户用CREATE TABLE命令创建一个分区表时,数据库会创建用户指定的表(根分区或者父表),还会基于用户指定的分区层次创建表的层次(子表)。分区表、子表和它们的继承层次关系通过系统视图pg_partitions跟踪。

对于一个含有被交换为使用外部表的叶子子分区的分区表,ANALYZE不会为外部表分区收集统计信息:

  • 如果ANALYZE [ROOTPARTITION]被运行,外部表不会被采样并且根表统计信息不包括外部表分区。
  • 如果在外部表分区上运行ANALYZE,该分区不会被分析。
  • 如果指定了VERBOSE子句,会显示一个报告消息:skipping external table.

数据库服务器配置参数 optimizer_analyze_root_partition 影响何时在分区表的根分区上收集统计信息。如果该参数被启用,当用户运行ANALYZE(没有ROOTPARTITON关键词)并且指定根分区时,会在根分区上收集统计信息。

ANALYZE收集的统计信息通常包括每个列中一些最常见值构成的列表以及显示每列中近似数据分布的柱状图。如果ANALYZE觉得对两者中的一个或者全部不感兴趣(例如,在一个唯一键列中,其中没有常见值)或者该列的数据类型不支持合适的操作符,它可能会忽略它们。

对于大型表,ANALYZE会取得该表内容的一份随机采样,而不是检查每一行。这允许非常大的表在很短的时间内被分析完。不过要注意,这样的统计信息只是近似的,并且即使实际表内容没有改变,统计信息也将会在每次运行ANALYZE后发生少许变化。这可能会导致EXPLAIN所显示的规划器估计代价出现少许变化。在很少见的情况下,这无疑将导致在两次ANALYZE运行之间查询优化器选择不同的查询计划。
为了避免这种情况,可以通过调整default_statistics_target配置参数增加ANALYZE收集的统计信息量,或者逐列用ALTER TABLE ... ALTER COLUMN ... SET STATISTICS(见ALTER TABLE)设置每列的统计信息目标。该目标值设置最常见值列表中的最大项数以及柱状图中的最大箱数。默认的目标值是10,但可以改变它以平衡规划器估计精度以及ANALYZE所花的时间和在pg_statistic中所占用的空间。特别地,将统计信息目标设置为零会禁用该列的统计信息收集。对那些从不出现在查询的WHERE、GROUP BY或者ORDER BY子句中的列来说,这可能会很有用,因为规划器将不会使用这类列上的统计信息。

被分析列中最大的统计信息目标决定了为准备统计信息要采样的表行数。增加该目标会导致执行ANALYZE所需的时间空间成比例增加。

当数据库执行一次ANALYZE操作为一个表收集统计信息并且检测到所有被采样表的数据页为空(不含有效数据)时,数据库会显示应该执行一次VACUUM FULL操作的消息。如果被采样页为空,该表的统计信息将不准确。页面会在对表的大量更新后变为空,例如删除了大量行。一次VACUUM FULL操作会移除空页并且允许ANALYZE操作收集准确的统计信息。

如果表没有统计信息,服务器配置参数 gp_enable_relsize_collection 控制传统查询优化器是否使用默认统计信息文件或者使用pg_relation_size函数估算表的尺寸。默认情况下,如果统计信息不可用,传统优化器使用默认统计信息文件来估算行数。

示例

为表mytable收集统计信息:

ANALYZE mytable;

兼容性

SQL标准中没有ANALYZE语句。

另见

ALTER TABLE、 EXPLAIN、 VACUUM