vacuum和analyze最佳实践(译)

译自:https://www.2ndquadrant.com/en/blog/postgresql-vacuum-and-analyze-best-practice-tips/

VACUUM和ANALYZE是PostgreSQL 数据库维护最重要的两个操作。
vacuum用于恢复表中“死元组”占用的空间。删除或更新(删除后插入)记录时,将产生死元组。PostgreSQL不会从表中物理删除旧行,而是在其上放置一个“标记”,以便查询不会返回该行。当vacuum进程运行时,这些死元组占用的空间被标记为可由其他元组重用。
“analyze”顾名思义——它分析数据库表的内容,并收集有关每个表的每一列值分布的统计信息。PostgreSQL 查询引擎使用这些统计信息来查找最佳执行计划。在数据库中插入、删除和更新行时,列统计信息也会更改。analyze——由DBA手动运行,或在auto vacuum后由PostgreSQL自动运行——确保统计数据是最新的。
虽然听起来相对简单,但幕后的vacuum和analyze是两个复杂的过程。幸运的是,DBA不必担心他们的内部结构。但是,他们经常对手动运行这些进程或为配置参数设置最佳值感到困惑。
在本文中,我们将分享一些vacuum和analyze的最佳实践。

Tip1:不要无缘无故地手动运行vacuum或analyze

PostgreSQL vacuum(autovacuum或手动vacuum)可最大程度地减少表膨胀并防止事务ID回卷。autovacuum不会恢复死元组占用的磁盘空间。但是,运行VACUUM FULL命令即可执行此操作。不过,vacuum full有其性能影响。目标表在操作期间被独占锁定,甚至无法读取表。该过程还会创建表的完整副本,这在运行时需要额外的磁盘空间。我们建议不要运行VACUUM FULL,除非存在非常高的膨胀百分比,并且查询受到严重影响。我们还建议为其提供数据库低活动周期去运行。
最好不要在整个数据库上过于频繁地运行手动清空;目标数据库可能已经通过自动真空过程进行了最佳清空。因此,手动清空可能不会删除任何死元组,但会导致不必要的 I/O 负载或 CPU 峰值。如有必要,手动吸尘器应仅在需要时逐个表运行,例如活动行与死行的比率低,或自动吸尘器之间的间隙较大。此外,应在用户活动最少时运行手动吸尘器。
Autovacuum还会使表的数据分布统计信息保持为最新(它不会重建它们)。手动运行时,ANALYZE 命令实际上会重建这些统计信息,而不是更新它们。同样,当统计数据已经最佳时通过常规autovacuum进行更新,重建统计信息可能会对系统资源造成不必要的压力。
必须手动运行ANALYZE的时间是立即在大容量数据加载到目标表之后。现有表中的大量(甚至几百个)新行将显著倾斜其列数据分布。新行将导致任何现有列统计信息过久。当查询优化器使用此类统计信息时,查询性能可能会非常慢。在这些情况下,在数据加载后立即运行 ANALYZE 命令以完全重建统计信息是比等待autovacuum启动更好的选择。

Tip2:微调autovacuum阈值

必须检查或调整autovacuum,并分析postgresql.conf文件或单个表属性中的配置参数,以便在autovacuum和性能提升之间取得平衡。
PostgreSQL使用两个配置参数来决定何时启动autovacuum:
autovacuum_vacuum_threshold:默认值为 50
autovacuum_vacuum_scale_factor:默认值为 0.2
这些参数一起告诉 PostgreSQL 在表中的死元组超过表中的行数乘以factor加上vacuum threshold时autovacuum。换句话说,PostgreSQL将在以下情况下在表上启动autovacuum:
pg_stat_user_tables.n_dead_tup > (pg_class.reltuples x autovacuum_vacuum_scale_factor) + autovacuum_vacuum_threshold
对于中小型表,这可能就足够了。例如,对于包含 10000 行的表,在autovacuum开始之前,死行数必须超过 2050 ((10000 x 0.2) + 50)。
并非数据库中的每个表都有相同的数据修改速率。通常,几个大表会经历频繁的数据修改,因此会有更多的死行。默认值可能不适用于此类表。例如,使用默认值时,具有 100 万行的表在autovacuum开始之前需要有超过 200050 个死行 ((1000000 x 0.2) + 50)。这可能意味着autovacuum之间的间隔更长,autovacuum时间越来越长,更糟糕的是,如果表上的活动事务锁定它,自动真空根本不运行。
因此,目标应该是将这些阈值设置为最佳值,以便autovacuum可以定期发生,并且不会花费很长时间(并影响用户会话),同时保持相对较低的死行数。
一种方法是使用其中一个参数。因此,如果我们将autovacuum_vacuum_scale_factor设置为0,而将autovacuum_vacuum_threshold设置为5000,则当一个表的死行数超过 5000 时,该表将autovacuum。

Tip3:微调auto analyze阈值

与autovacuum类似,auto analyze也使用两个参数来决定autovacuum何时也会触发auto analyze(auto analyze也使用autovacuum进程工作):
autovacuum_analyze_threshold:默认值为 50
autovacuum_analyze_scale_factor:默认值为 0.1
与autovacuum一样,autovacuum_analyze_threshold 参数可以设置为一个值,该值指示在auto analyze开始之前在表中插入、删除或更新的元组数。我们建议在大型和高事务表上单独设置此参数。表配置将覆盖 postgresql.conf值。
下面的代码片段显示了用于修改表的autovacuum_analyze_threshold设置的 SQL 语法。

ALTER TABLE <table_name> 
SET (autovacuum_analyze_threshold = <threshold rows>)

Tip4:微调autovacuum workers

另一个经常被DBA忽略的参数是autovacuum_max_workers,它的默认值为 3。autovacuum不是一个单一的进程,而是多个并行运行的进程。指定多个工作线程的原因是为了确保vacuum大型表不会阻碍vacuum较小的表和用户会话。autovacuum_max_workers参数告诉PostgreSQL启动autovacuum多少进程来进行清理。
PostgreSQL DBA的一个常见做法是增加最大工作线程的数量,希望它能加速autovacuum。这不起作用,因为所有线程共享同一个autovacuum_vacuum_cost_limit,默认值为 200。使用如下所示的公式为每个autovacuum进程分配成本限制:
individual thread’s cost_limit = autovacuum_vacuum_cost_limit / autovacuum_max_workers
autovacuum进程完成的工作成本使用三个参数计算:

  • vacuum_cost_page_hit:默认值为 1
  • vacuum_cost_page_miss:默认值为 10
  • vacuum_cost_page_dirty:默认值为 20
    这些参数的含义是:
  • 当autovacuum在共享缓冲区中找到它应该清理的数据页时,开销为 1。
  • 如果数据页不在共享缓冲区中,而是位于操作系统缓存中,则开销将为 10。
  • 如果由于autovacuum必须删除死元组而必须将页面标记为脏页面,则成本将为 20。

worker数量的增加将降低每个线程的成本限制。由于每个线程都被分配了较低的成本限制,因此由于很容易达到成本阈值,它将更频繁地进入睡眠状态,最终导致整个vacuum过程运行缓慢。建议将autovacuum_vacuum_cost_limit增加到更高的值(如 2000),然后调整最大工作进程数。
更好的方法是仅在必要时为单个表调整这些参数。例如,如果大型事务表的autovacuum时间过长,则可以暂时将该表配置为使用其自己的清空成本限制和成本延迟。成本限制和延迟将覆盖postgresql.conf中设置的系统范围的值。
下面的代码片段显示了如何配置各个表。

ALTER TABLE <table_name> SET (autovacuum_vacuum_cost_limit = <large_value>)
ALTER TABLE <table_name> SET (autovacuum_vacuum_cost_delay = <lower_cost_delay>)

使用第一个参数将确保分配给表的autovacuum进程在进入睡眠状态之前将执行更多工作。降低autovacuum_vacuum_cost_delay也意味着线程休眠的时间更少。

最后的思考

如你所见,更改vacuum和analyze的配置参数很简单,但首先需要仔细观察。每个数据库在大小、流量模式和事务速率方面都不同。我们建议DBA在更改参数或推出手动vacuum/analyze制度之前,首先收集足够有关的数据库信息。此类信息可以是:

  • 每个表中的行数
  • 每个表中的死元组数
  • 每个表的最后一次vacuum时间
  • 每个表的上次analyze时间
  • 每个表中数据插入/更新/删除的速率
  • 每个表autovacuum所花费的时间
  • 有关表未autovacuum的警告
  • 大多数关键查询及其访问的表的当前性能
  • 手动vacuum/analyze后相同的查询的性能

到这,DBA可以选择几个“试点”表来开始优化。他们可以开始更改表的vacuum/analyze属性并检查性能。PostgreSQL是一个智能数据库引擎——DBA通常会发现最好让PostgreSQL进行vacuum和analyze,而不是手动执行。

猜你喜欢

转载自blog.csdn.net/qq_40687433/article/details/130814627