ANALYZE — 收集有关一个数据库的统计信息
ANALYZE [ (option
[, ...] ) ] [table_and_columns
[, ...] ] ANALYZE [ VERBOSE ] [table_and_columns
[, ...] ] 其中option
可以是: VERBOSE [boolean
] SKIP_LOCKED [boolean
]table_and_columns
是:table_name
[ (column_name
[, ...] ) ]
ANALYZE
收集一个数据库中的表的内容的统计信息,并且将结果存储在pg_statistic
系统目录中。接下来,查询优化器会使用这些统计信息来帮助确定查询最有效的执行计划。
如果没有table_and_columns
列表,则ANALYZE
处理当前用户有权分析的当前数据库中的每个表。使用列表,ANALYZE
仅处理那些表。还可以给出表的列名列表,在这种情况下,仅收集这些列的统计信息。
当选项列表用括号括起来时,选项可以按任何顺序来写。 带括号的语法是在LightDB 11中添加的;不带括号的语法已弃用。
VERBOSE
允许显示进度消息。
SKIP_LOCKED
规定ANALYZE
在开始处理一个关系时不应等待任何冲突的锁被释放:如果关系不能无需等待立即锁定,则跳过该关系。
请注意即使采用此选项,ANALYZE
在打开关系的索引或从分区、表继承子级和某些类型的外表获取样本行时仍可能阻塞。
此外,当ANALYZE
通常处理指定分区表的所有分区时,如果分区表上有一个冲突的锁,这个选项将导致ANALYZE
跳过所有分区表。
boolean
规定所选的选项打开或关闭。
您可以写TRUE
、ON
或1
以启用该选项,或者是FALSE
、OFF
或0
来禁用它。
boolean
值可以被省略,在假定为TRUE
的情况下。
table_name
要分析的一个指定表的名称(可以是模式限定的)。如果省略,则分析当前数据库中的所有常规表、分区表(但不包含外部表)。 如果指定的表是分区表,则整个分区表的继承统计信息和各个分区的统计信息都将更新。
column_name
要分析的一个指定列的名称。默认是所有列。
当指定了VERBOSE
时,ANALYZE
会发出进度消息来指示当前正在处理哪个表。还会打印有关那些表的多种统计信息。
要分析表,通常必须是该表的所有者或超级用户。不过,数据库所有者可以分析数据库中的所有表,共享目录除外。
(对共享目录的限制意味着真正的数据库范围的ANALYZE
只能由超级用户执行。)
ANALYZE
将跳过调用用户没有分析权限的任何表。
只有被显式选中时才会分析外部表。并非所有外部数据包装器都支持ANALYZE
。如果表的包装器不支持ANALYZE
,该命令会打印一个警告并且什么也不做。
在默认的LightDB配置中,自动清理守护进程(见Section 23.1.6)会在表第一次载入数据或者用常规操作改变时负责表的自动分析。当启用自动清理时,定期运行ANALYZE
是个好主意,或者可以在表内容做了大的修改后运行ANALYZE
。准确的统计信息将帮助优化器选择最合适的查询计划,从而提升查询处理的速度。主读数据库的一般策略是在一天中使用量最低时运行一次VACUUM
和ANALYZE
(如果有大量的更新动作则是不够的)。
ANALYZE
只要求目标表上的一个读锁,因此它可以和表上的其他动作并行。
ANALYZE
收集的统计信息通畅包括每列中最常见值的列表以及展示每列中近似数据分布的一个直方图。如果ANALYZE
认为这些东西无趣(例如在一个唯一键列中,没有共同值)或者该列的数据类型不支持合适的操作符,以上工作都会被省略。在Chapter 23中有与统计信息相关的更多信息。
对于大型的表,ANALYZE
会对表内容做随机采样而不是检查每一行。这允许在很少的时间内完成对大型表的分析。不过要注意,这些统计信息只是近似值,并且即使实际表内容没有改变,每次运行ANALYZE
时统计信息都会有微小地改变。这可能会导致EXPLAIN
显示的优化器估算代价有小的改变。在很少的情况下,这会非决定性地导致优化器的查询计划选择在ANALYZE
运行后改变。为了避免这种情况,可以按照下文所述提高ANALYZE
所收集的统计信息量。
通过调整default_statistics_target配置变量可以控制分析量,对每个列可以用ALTER TABLE ... ALTER COLUMN ... SET STATISTICS
设置每列的统计信息目标。目标值会设置最常用值列表中的最大项数以及直方图中的最大容器数。默认目标值是 100,可以把它调大或者调小在优化器估计值精度和ANALYZE
花费的时间以及pg_statistic
所占空间之间做出平衡。特别地,将统计信息目标设置为零会禁用该列的统计信息收集。在查询的WHERE
、GROUP BY
或者ORDER BY
子句中从不出现的列上这样做会有所帮助,因为优化器用不上这些列上的统计信息。
被分析的列中最大的统计信息目标决定了为准备统计信息要采样的表行数。增加该目标会导致做ANALYZE
所需的时间和空间成比例增加。
ANALYZE
所估算的值之一是出现在每个列中的可区分值。因为只会检查行的一个子集,即便使用最大的统计信息目标,这种估计有时也可能很不精确。如果这种不精确导致不好的查询计划,可以手工确定一个更精确的值并且用ALTER TABLE ... ALTER COLUMN ... SET (n_distinct = ...)
设置该值。
如果被分析的表有一个或者更多子女,ANALYZE
将会收集两次统计信息:一次只对父表的行收集,第二次则在父表及其所有子女表的行上收集。在规划需要遍历整个继承树的查询时需要第二个统计信息集。不过,在决定是否触发表上的自动分析时,自动清理后台进程将只考虑父表本身上的插入和更新。如果该表很少被插入或者更新,只有手工运行ANALYZE
时才会把继承统计信息更新到最新。
对于分区表,ANALYZE
通过对所有分区中的行进行采样来收集统计信息;此外,它将递归到每个分区并更新其统计信息。即使使用多级分区,每个叶分区也只分析一次。只收集父表的统计信息(没有来自其分区的数据),因为使用分区可以保证它是空的。
相比之下,如果要分析的表具有继承子表,则ANALYZE
会收集两组统计信息:一组仅针对父表的行,另一组包括父表及其所有子表的行。当计划将继承树作为一个整体进行处理的查询时,需要第二组统计信息。在这种情况下,不会单独分析子表本身。
autovacuum守护进程不处理分区表,也不处理继承父级(如果只修改了子级)。通常需要定期运行手动ANALYZE
,以保持表层次结构的统计信息是最新的。
如果任何子表是外部表并且其外部数据包装器不支持ANALYZE
,在收集继承统计信息时会忽略那些子表。
如果被分析的表不完全为空,ANALYZE
将不会为该表记录新统计信息。任何现有统计信息将会被保留。
SQL 标准中没有ANALYZE
语句。