

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

# 診斷資料表和索引膨脹
<a name="AuroraPostgreSQL.diag-table-ind-bloat"></a>

您可以使用 PostgreSQL 多版本並行控制 (MVCC) 來協助維護資料的完整性。PostgreSQL MVCC 的運作方式是儲存更新或刪除的資料列 (*元組*) 內部複本，直到交易提交或復原。使用者看不到這份儲存的內部複本。但是，若 VACUUM 或 AUTOVACUUM 公用程式未定期清理這些隱藏複本，便可能發生資料表膨脹。不選取，資料表膨脹可能會增加儲存成本並降低處理速度。

在許多情況下，Aurora 上 VACUUM 或 AUTOVACUUM 的預設設定足夠處理不需要的資料表膨脹。但是，若您的應用程式遇到以下情況，可能需要檢查膨脹情形：
+ 在 VACUUM 程序間的較短時間內處理大量交易。
+ 執行效果不佳且儲存空間不足。

若要開始使用，請取得失效元組使用空間量的準確資訊，以及您能透過清理資料表和索引膨脹來復原的空間量。若要這麼做，請使用 `pgstattuple` 擴充功能來取得 Aurora 叢集上的統計資料。如需更多詳細資訊，請參閱 [pgstattuple](https://www.postgresql.org/docs/current/pgstattuple.html)。只有 `pg_stat_scan_tables` 角色和資料庫超級使用者能使用 `pgstattuple` 擴充功能。

若要在 Aurora 上建立 `pgstattuple` 擴充功能，請將用戶端工作階段連線到叢集，例如 psql 或 pgAdmin，然後使用下列命令：

```
CREATE EXTENSION pgstattuple;
```

在您要設定的每個資料庫中建立擴充功能。建立擴充功能之後，請使用命令列界面 (CLI) 來計算您可以收回多少無法使用的空間。在取得統計資料之前，請先將 AUTOVACTURE 設為 0，以修改叢集參數群組。將該值設為 0 可防止 Aurora 自動清除應用程式留下的任何失效元組，進而影響結果準確性。輸入下列命令建立簡易資料表：

```
postgres=> CREATE TABLE lab AS SELECT generate_series (0,100000);
SELECT 100001
```

在下方範例中，我們在啟用 AUTOVACUUM 的情況下執行資料庫叢集查詢。`dead_tuple_count` 為 0，表示 AUTOVACUUM 已從 PostgreSQL 資料庫刪除過時的資料或元組。

若要以 `pgstattuple` 來取得資料表相關資訊，請在查詢中指定資料表名稱或物件識別碼 (OID)：

```
postgres=> SELECT * FROM pgstattuple('lab');
```

```
    
    
table_len  | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
3629056    | 100001      | 2800028   | 77.16         | 0                | 0              | 0                  | 16616      | 0.46
(1 row)
```

在下方的查詢中，我們關閉 AUTOVACUUM 並輸入命令，從資料表中刪除 25,000 資料列。結果是，`dead_tuple_count` 增加到 25000。

```
postgres=> DELETE FROM lab WHERE generate_series < 25000;    

DELETE 25000
```

```
SELECT * FROM pgstattuple('lab');
```

```
        
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
3629056 | 75001 | 2100028 | 57.87 | 25000 | 700000 | 19.29 | 16616 | 0.46
(1 row)
```

若要回收這些無效元組，請啟動 VACUUM 程序。

## 在不中斷應用程式的情況下觀察膨脹情形
<a name="AuroraPostgreSQL.diag-table-ind-bloat.Observing"></a>

Aurora 叢集上的設定經過最佳化，可為多數工作負載提供最佳實務。不過，您可能想最佳化叢集，以更符合您的應用程式和使用模式。在此情況下，您可以使用 `pgstattuple` 擴充功能，且不會中斷忙碌的應用程式。若要這麼做，請執行下列步驟：

1. 複製您的 Aurora 執行個體。

1. 修改參數檔案，以關閉複製中的 AUTOVACUUM。

1. 執行 `pgstattuple` 查詢時以範例工作負載或 pgbench 測試複製，pgbench 是在 PostgreSQL 上執行基準測試的程式。如需更多詳細資訊，請參閱 [pgbench](https://www.postgresql.org/docs/current/pgbench.html)。

執行應用程式並檢視結果之後，請在還原的複本上使用 pg\_repack 或 VACUUM FULL 並比較差異。若 dead\_tuple\_count、dead\_tuple\_len 或 dead\_tuple\_percent 的值顯著下降，請調整生產叢集上的真空排程，盡量減少膨脹。

## 避免暫存資料表膨脹
<a name="AuroraPostgreSQL.diag-table-ind-bloat.AvoidinginTables"></a>

若您的應用程式要建立暫存資料表，請確認應用程式會在不需要暫存資料表後進行移除。自動清空程序找不到暫存資料表。保持不選取，暫存資料表可以快速建立資料庫膨脹。此外，膨脹可以擴展到系統資料表，也就是追蹤 PostgreSQL 物件和屬性的內部資料表，例如 pg\_attribute 和 pg\_depend。

當不再需要暫存資料表時，您可以使用 TRUNCATE 陳述式來清空資料表並釋放空間。然後，手動清空 pg\_attribute 和 pg\_depend 資料表。清空這些資料表，確保不斷建立和截斷/刪除暫存資料表時，不會新增元組並導致系統膨脹。

您可以在建立暫存資料表時避免這個問題，方法是加入下列語法，在提交內容時刪除新資料列：

```
CREATE TEMP TABLE IF NOT EXISTS table_name(table_description) ON COMMIT DELETE ROWS;
```

遞交交易時，`ON COMMIT DELETE ROWS` 子句會截斷暫存資料表。

## 避免索引膨脹
<a name="AuroraPostgreSQL.diag-table-ind-bloat.AvoidinginIndexes"></a>

變更資料表的索引欄位時，索引更新會導致該索引出現一或多個失效元組。根據預設，自動清空程序會清除索引中的膨脹，但是該清理程序會佔用大量時間和資源。若要在建立資料表時指定索引清理偏好設定，請包括 vacuum\_index\_cleanup 子句。根據預設，建立資料表時，子句會設為 AUTO，表示伺服器會決定索引在清空資料表時是否需要進行清除。您可以將子句設為 ON 以開啟特定資料表的索引清除，或設為 OFF 關閉該資料表的索引清除。請留意，關閉索引清除可能會節省時間，但同時也可能導致索引膨脹。

清空資料表時，您可以在命令列中手動控制索引清除。若要清空資料表並從索引中刪除失效元組，請包括值設為 ON 的 INDEX\_CLEANUP 子句和資料表名稱：

```
acctg=> VACUUM (INDEX_CLEANUP ON) receivables;
        
INFO: aggressively vacuuming "public.receivables"
VACUUM
```

若要在不清除索引的情況下清空資料表，請將值設為 OFF：

```
acctg=> VACUUM (INDEX_CLEANUP OFF) receivables;
        
INFO: aggressively vacuuming "public.receivables"
VACUUM
```