

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 手動清空和分析資料表
<a name="manual-vacuum"></a>

如果您的資料庫是由自動清空程序清空，最佳實務是避免太頻繁地在整個資料庫上執行手動清空。手動清空可能會導致不必要的 I/O 負載或 CPU 峰值，也可能無法移除任何無效元組。只有在真正必要的情況下，例如即時元組與無效元組的比例很低，或自動清空之間存在長間隙時，才能逐table-by-table執行手動清空。此外，您應該在使用者活動最少時執行手動清空。

自動清空也會將資料表的統計資料保持在最新狀態。當您手動執行`ANALYZE`命令時，它會重建這些統計資料，而不是更新它們。當一般自動清空程序已經更新統計資料時，重建統計資料可能會導致系統資源使用率。

建議您在下列情況下手動執行 [VACUUM](https://www.postgresql.org/docs/current/sql-vacuum.html) 和 [ANALYZE](https://www.postgresql.org/docs/current/sql-analyze.html) 命令：
+ 在忙碌資料表的低尖峰時間，自動清空可能不夠。
+ 在您立即將資料大量載入目標資料表之後。在此情況下，`ANALYZE`手動執行會完全重建統計資料，這是比等待自動清空開始更好的選項。
+ 清空暫存資料表 （自動清空無法存取）。

若要在並行資料庫活動上執行 `VACUUM`和 `ANALYZE`命令時減少 I/O 影響，您可以使用 `vacuum_cost_delay` 參數。在許多情況下，維護命令如 `VACUUM`和 `ANALYZE`不需要快速完成。不過，這些命令不應干擾系統執行其他資料庫操作的能力。若要避免這種情況，您可以使用 `vacuum_cost_delay` 參數啟用成本型清空延遲。根據預設，手動發出的`VACUUM`命令會停用此參數。若要啟用它，請將其設定為非零值。

## 平行執行清空和清除操作
<a name="manual-vacuum-parallel"></a>

`VACUUM` 命令 [PARALLEL](https://www.postgresql.org/docs/current/sql-vacuum.html) 選項會將平行工作者用於索引清空和索引清除階段，並預設為停用。平行工作者的數量 （平行處理的程度） 取決於資料表中的索引數量，並且可由使用者指定。如果您是在沒有整數引數的情況下執行平行`VACUUM`操作，則會根據資料表中的索引數目來計算平行處理的程度。

下列參數可協助您在 Amazon RDS for PostgreSQL 和 Aurora PostgreSQL 相容中設定平行清空：
+ [max\_worker\_processes](https://www.postgresql.org/docs/current/runtime-config-resource.html) 會設定並行工作者程序的數目上限。
+ [min\_parallel\_index\_scan\_size](https://www.postgresql.org/docs/current/runtime-config-query.html) 會設定必須掃描才能考慮平行掃描的最低索引資料量。
+ [max\_parallel\_maintenance\_workers](https://www.postgresql.org/docs/current/runtime-config-resource.html) 會設定單一公用程式命令可啟動的平行工作者數量上限。

**注意**  
`PARALLEL` 選項僅用於清空目的。它不會影響 `ANALYZE`命令。

下列範例說明您在資料庫上使用手動 `VACUUM` 和 `ANALYZE` 時的資料庫行為。

以下是已停用自動清空的範例資料表 （僅用於說明目的；不建議停用自動清空）：

```
create table t1 ( a int, b int, c int );
alter table t1 set (autovacuum_enabled=false);
```

```
apgl=> \d+ t1
Table "public.t1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+---------+--------------+-------------
a | integer | | | | plain | |
b | integer | | | | plain | |
c | integer | | | | plain | |
Access method: heap
Options: autovacuum_enabled=false
```

將 100 萬列新增至資料表 t1：

```
apgl=> select count(*) from t1;
count
1000000
(1 row)
```

資料表 t1 的統計資料：

```
select * from pg_stat_all_tables where relname='t1';
-[ RECORD 1 ]-------+--------
relid         | 914744
schemaname    | public
relname       | t1
seq_scan      | 0
seq_tup_read  | 0
idx_scan      |
idx_tup_fetch |
n_tup_ins     | 1000000
n_tup_upd     | 0
n_tup_del     | 0
n_tup_hot_upd | 0
n_live_tup    | 1000000
n_dead_tup    | 0
n_mod_since_analyze | 1000000
last_vacuum      |
last_autovacuum  |
last_analyze     |
last_autoanalyze |
vacuum_count     | 0
autovacuum_count | 0
analyze_count    | 0
autoanalyze_count | 0
```

新增索引：

```
create index i2 on t1 (b,a);
```

執行 `EXPLAIN`命令 （計劃 1)：

```
Bitmap Heap Scan on t1 (cost=10521.17..14072.67 rows=5000 width=4)
Recheck Cond: (a = 5)
→ Bitmap Index Scan on i2 (cost=0.00..10519.92 rows=5000 width=0)
Index Cond: (a = 5)
(4 rows)
```

執行 `EXPLAIN ANALYZE`命令 （計劃 2)：

```
explain (analyze,buffers,costs off) select a from t1 where b = 5;
QUERY PLAN
Bitmap Heap Scan on t1 (actual time=0.023..0.024 rows=1 loops=1)
Recheck Cond: (b = 5)
Heap Blocks: exact=1
Buffers: shared hit=4
→ Bitmap Index Scan on i2 (actual time=0.016..0.016 rows=1 loops=1)
Index Cond: (b = 5)
Buffers: shared hit=3
Planning Time: 0.054 ms
Execution Time: 0.076 ms
(9 rows)
```

`EXPLAIN `和 `EXPLAIN ANALYZE `命令會顯示不同的計劃，因為資料表上已停用自動清空，且`ANALYZE`命令未手動執行。現在，讓我們更新資料表中的值，並重新產生`EXPLAIN ANALYZE`計劃：

```
update t1 set a=8 where b=5;
explain (analyze,buffers,costs off) select a from t1 where b = 5;
```

`EXPLAIN ANALYZE` 命令 （計劃 3) 現在會顯示：

```
apgl=> explain (analyze,buffers,costs off) select a from t1 where b = 5;
QUERY PLAN
Bitmap Heap Scan on t1 (actual time=0.075..0.076 rows=1 loops=1)
Recheck Cond: (b = 5)
Heap Blocks: exact=1
Buffers: shared hit=5
→ Bitmap Index Scan on i2 (actual time=0.017..0.017 rows=2 loops=1)
Index Cond: (b = 5)
Buffers: shared hit=3
Planning Time: 0.053 ms
Execution Time: 0.125 ms
```

如果您比較計畫 2 和計畫 3 之間的成本，您會看到規劃和執行時間的差異，因為我們尚未收集統計資料。

現在，讓我們在資料表`ANALYZE`上執行手冊，然後檢查統計資料並重新產生計劃：

```
apgl=> analyze t1
apgl→ ;
ANALYZE
Time: 212.223 ms

apgl=> select * from pg_stat_all_tables where relname='t1';
-[ RECORD 1 ]-------+------------------------------
relid          | 914744
schemaname     | public
relname        | t1
seq_scan       | 3
seq_tup_read   | 1000000
idx_scan       | 3
idx_tup_fetch  | 3
n_tup_ins      | 1000000
n_tup_upd      | 1
n_tup_del      | 0
n_tup_hot_upd  | 0
n_live_tup     | 1000000
n_dead_tup     | 1
n_mod_since_analyze | 0
last_vacuum       |
last_autovacuum   |
last_analyze      | 2023-04-15 11:39:02.075089+00
last_autoanalyze  |
vacuum_count      | 0
autovacuum_count  | 0
analyze_count     | 1
autoanalyze_count | 0

Time: 148.347 ms
```

執行 `EXPLAIN ANALYZE`命令 （計劃 4)：

```
apgl=> explain (analyze,buffers,costs off) select a from t1 where b = 5;
QUERY PLAN
Index Only Scan using i2 on t1 (actual time=0.022..0.023 rows=1 loops=1)
Index Cond: (b = 5)
Heap Fetches: 1
Buffers: shared hit=4
Planning Time: 0.056 ms
Execution Time: 0.068 ms
(6 rows)

Time: 138.462 ms
```

如果您在手動分析資料表並收集統計資料後比較所有計畫結果，您會注意到最佳化工具的計畫 4 優於其他計畫，並縮短查詢執行時間。此範例顯示對資料庫執行維護活動的重要性。

## 使用 VACUUM FULL 重寫整個資料表
<a name="manual-vacuum-full"></a>

使用 `FULL` 參數執行 `VACUUM `命令會將資料表的整個內容重新寫入新的磁碟檔案，而不會有額外的空間，並將未使用的空間傳回至作業系統。此操作速度較慢，且每個資料表都需要`ACCESS EXCLUSIVE`鎖定。它還需要額外的磁碟空間，因為它會寫入資料表的新複本，而且在操作完成之前不會釋出舊複本。

`VACUUM FULL` 在下列情況下， 很有用：** **
+ 當您想要從資料表回收大量空間時。
+ 當您想要在非主索引鍵資料表中回收膨脹空間時。

如果您的資料庫可以容忍停機時間，我們建議您在有非主索引鍵資料表`VACUUM FULL`時使用 。

由於 `VACUUM FULL`需要比其他 操作更多的鎖定，因此在關鍵資料庫上執行會更昂貴。若要取代此方法，您可以使用 `pg_repack `延伸，[如下一節](pg-repack.md)所述。此選項類似於 `VACUUM FULL`，但需要最低限度的鎖定，Amazon RDS for PostgreSQL 和 Aurora PostgreSQL 相容皆支援。