

 Amazon Redshift 將不再支援從修補程式 198 開始建立新的 Python UDFs。現有 Python UDF 將繼續正常運作至 2026 年 6 月 30 日。如需詳細資訊，請參閱[部落格文章](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)。

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

# 分析資料表
<a name="t_Analyzing_tables"></a>

ANALYZE 操作可更新查詢規劃器用來選擇最佳計畫的統計中繼資料。

在大多數情況下，您不需要明確執行 ANALYZE 命令。Amazon Redshift 會監控工作負載的變更，並在背景自動更新統計資料。此外，COPY 命令在將資料載入至空白資料表時會自動執行分析。

若要明確分析資料表或整個資料庫，請執行 [ANALYZE](r_ANALYZE.md) 命令。

## 自動分析
<a name="t_Analyzing_tables-auto-analyze"></a>

Amazon Redshift 會持續監控資料庫，並自動在背景中執行分析操作。為了盡量減少對系統效能的影響，自動分析會在工作負載較低期間執行。

預設會啟用自動分析。若要關閉自動分析，請修改叢集的參數群組，將 `auto_analyze` 參數設為 **false**。

為了減少處理時間並提高整體系統效能，對於修改程度較小的任何資料表，Amazon Redshift 會略過自動分析。

分析操作會略過有最新統計資訊的資料表。如果您在擷取、轉換和載入 (ETL) 工作流程中執行 ANALYZE，自動分析會略過有最新統計資訊的資料表。同樣地，當自動分析已更新資料表的統計資訊時，明確 ANALYZE 會略過資料表。

## 新資料表資料的分析
<a name="t_Analyzing_tables-new-tables"></a>

 依預設，COPY 命令在將資料載入至空白資料表之後會執行 ANALYZE。設定 STATUPDATE ON，即可以強制 ANALYZE 而不論資料表是否空白。如果您指定 STATUPDATE OFF，則不會執行 ANALYZE。將 STATUPDATE 設為 ON 時，只有資料表擁有者或超級使用者可以執行 ANALYZE 命令或執行 COPY 命令。

Amazon Redshift 也會分析您使用下列命令建立的新資料表：
+ CREATE TABLE AS (CTAS) 
+ CREATE TEMP TABLE AS 
+ SELECT INTO 

對最初載入資料後未分析的新資料表執行查詢時，Amazon Redshift 會傳回警告訊息。在後續更新或載入之後查詢資料表時不會發生警告。如果查詢所參考的資料表尚未分析，當您在該資料表上執行 EXPLAIN 命令時，將會傳回相同的警告訊息。

每當將資料新增至非空白資料表就會大幅改變資料表大小時，您可以明確更新統計資訊。若要這麼做，請執行 ANALYZE 命令，或在 COPY 命令中使用 STATUPDATE ON 選項。若要檢視自前次 ANALYZE 以來插入或刪除的資料列數目的詳細資訊，請查詢 [PG\$1STATISTIC\$1INDICATOR](r_PG_STATISTIC_INDICATOR.md) 系統目錄資料表。

您可以將 [ANALYZE](r_ANALYZE.md) 命令的範圍指定為下列其中一項：
+ 整個目前資料庫
+ 單一資料表
+ 單一資料表中的一或多個特定資料欄
+ 可能用作查詢中述詞的資料欄

 ANALYZE 命令會從資料表取得資料列的樣本，執行一些計算，並儲存所產生的資料欄統計資訊。依預設，Amazon Redshift 會為 DISTKEY 資料欄執行一個樣本階段，以及為資料表中的所有其他資料欄執行另一個樣本階段。如果您想要為資料欄的子集產生統計資料，您可以指定以逗點分隔的資料欄清單。您可以搭配 PREDICATE COLUMNS 子句執行 ANALYZE，以略過未作為述詞的欄。

 ANALYZE 操作相當耗用資源，因此請僅對實際需要統計資料更新的資料表和資料欄執行。您不需要經常或按相同的排程分析所有資料表中的所有資料欄。如果資料本質上變更，請分析在下列項目中經常使用的資料欄：
+ 排序和群組操作
+ 聯結
+ 查詢述詞

為了減少處理時間並提高整體系統效能，對於變更的資料列百分比 (取決於 [analyze\$1threshold\$1percent](r_analyze_threshold_percent.md) 參數) 較低的任何資料表，Amazon Redshift 會略過 ANALYZE。依預設，分析閾值是設為 10%。您可以執行 [SET](r_SET.md) 命令來變更目前工作階段的分析閾值。

較不需要頻繁分析的資料欄為代表事實和量值的那些資料欄，以及實際上從不會查詢的任何相關屬性，例如大型 VARCHAR 資料欄。例如，考慮 TICKIT 資料庫中的 LISTING 資料表。

```
select "column", type, encoding, distkey, sortkey
from pg_table_def where tablename = 'listing';


column         |        type        | encoding | distkey | sortkey 
---------------+--------------------+----------+---------+---------
listid         | integer            | none     | t       | 1       
sellerid       | integer            | none     | f       | 0       
eventid        | integer            | mostly16 | f       | 0       
dateid         | smallint           | none     | f       | 0       
numtickets     | smallint           | mostly8  | f       | 0       
priceperticket | numeric(8,2)       | bytedict | f       | 0       
totalprice     | numeric(8,2)       | mostly32 | f       | 0       
listtime       | timestamp with...  | none     | f       | 0
```

如果此資料表每天會載入大量的新記錄，則必須經常分析在查詢中經常用作聯結索引鍵的 LISTID 資料欄。如果 TOTALPRICE 和 LISTTIME 是經常在查詢中使用的條件，您可以在週間每天分析這些資料欄和分佈索引鍵。

```
analyze listing(listid, totalprice, listtime);
```

假設應用程式中的銷售者和事件更為靜態，而日期 ID 參考僅涵蓋兩年或三年的固定一組日期。在此情況下，這些欄的唯一值不會大幅變更。不過，每個唯一值的執行個體數目將會穩定增加。

此外，考慮相較於 TOTALPRICE 資料欄，較不常查詢 NUMTICKETS 和 PRICEPERTICKET 量值的情況。在此情況下，您可以在每個週末對整個資料表執行一次 ANALYZE 命令，以更新沒有每日分析的五個欄的統計資訊：
<a name="t_Analyzing_tables-predicate-columns"></a>
**述詞欄位**  
做為指定資料欄清單的便利替代方案，您可以選擇僅分析可能用來作為述詞的資料列。執行查詢時，在聯結中使用的任何資料欄、篩選條件或群組依據子句會在系統目錄中標示為述詞資料欄。執行 ANALYZE 搭配 PREDICATE COLUMNS 子句時，分析操作只會包括符合以下條件的資料欄：
+ 此資料欄已標示為述詞資料欄。
+ 資料欄是分佈索引鍵。
+ 資料欄是排序索引鍵的一部分。

如果沒有任一個資料表的資料欄已標示為述詞，ANALYZE 會包括所有資料欄，即使指定了 PREDICATE COLUMNS 亦然。如果沒有資料欄已標示為述詞資料欄，可能是因為尚未查詢該資料表。

當您的工作負載的查詢模式相對穩定時，您可能選擇使用 PREDICATE COLUMNS。當查詢模式變動時，由於經常使用不同的資料欄做為述詞，使用 PREDICATE COLUMNS 可能會暫時造成過時的統計資料。過時的統計資料可能導致次佳的查詢執行期計劃和較長的執行期。不過，當您下次使用 PREDICATE COLUMNS 執行 ANALYZE 時，會包含新的述詞資料欄。

若要檢視述詞資料欄的詳細資訊，請使用下列 SQL 來建立名為 PREDICATE\$1COLUMNS 的檢視。

```
CREATE VIEW predicate_columns AS
WITH predicate_column_info as (
SELECT ns.nspname AS schema_name, c.relname AS table_name, a.attnum as col_num,  a.attname as col_name,
        CASE
            WHEN 10002 = s.stakind1 THEN array_to_string(stavalues1, '||') 
            WHEN 10002 = s.stakind2 THEN array_to_string(stavalues2, '||')
            WHEN 10002 = s.stakind3 THEN array_to_string(stavalues3, '||')
            WHEN 10002 = s.stakind4 THEN array_to_string(stavalues4, '||')
            ELSE NULL::varchar
        END AS pred_ts
   FROM pg_statistic s
   JOIN pg_class c ON c.oid = s.starelid
   JOIN pg_namespace ns ON c.relnamespace = ns.oid
   JOIN pg_attribute a ON c.oid = a.attrelid AND a.attnum = s.staattnum)
SELECT schema_name, table_name, col_num, col_name,
       pred_ts NOT LIKE '2000-01-01%' AS is_predicate,
       CASE WHEN pred_ts NOT LIKE '2000-01-01%' THEN (split_part(pred_ts, '||',1))::timestamp ELSE NULL::timestamp END as first_predicate_use,
       CASE WHEN pred_ts NOT LIKE '%||2000-01-01%' THEN (split_part(pred_ts, '||',2))::timestamp ELSE NULL::timestamp END as last_analyze
FROM predicate_column_info;
```

假設您對 LISTING 資料表執行下列查詢。請注意，聯結、篩選條件和群組依據子句中會使用 LISTID、LISTTIME 和 EVENTID。

```
select s.buyerid,l.eventid, sum(l.totalprice)
from listing l
join sales s on l.listid = s.listid
where l.listtime > '2008-12-01'
group by l.eventid, s.buyerid;
```

查詢 PREDICATE\$1COLUMNS 檢視時，如下列範例所示，您會看到 LISTID、EVENTID 和 LISTTIME 都標示為述詞欄。

```
select * from predicate_columns 
where table_name = 'listing';
```

```
schema_name | table_name | col_num | col_name       | is_predicate | first_predicate_use | last_analyze       
------------+------------+---------+----------------+--------------+---------------------+--------------------
public      | listing    |       1 | listid         | true         | 2017-05-05 19:27:59 | 2017-05-03 18:27:41
public      | listing    |       2 | sellerid       | false        |                     | 2017-05-03 18:27:41
public      | listing    |       3 | eventid        | true         | 2017-05-16 20:54:32 | 2017-05-03 18:27:41
public      | listing    |       4 | dateid         | false        |                     | 2017-05-03 18:27:41
public      | listing    |       5 | numtickets     | false        |                     | 2017-05-03 18:27:41
public      | listing    |       6 | priceperticket | false        |                     | 2017-05-03 18:27:41
public      | listing    |       7 | totalprice     | false        |                     | 2017-05-03 18:27:41
public      | listing    |       8 | listtime       | true         | 2017-05-16 20:54:32 | 2017-05-03 18:27:41
```

讓統計資料保持在最新狀態，可讓查詢規劃工具選擇最佳計劃，進而改善查詢效能。Amazon Redshift 會在背景自動重新整理統計資料，您也可以明確執行 ANALYZE 命令。如果您選擇明確執行 ANALYZE，請執行下列操作：
+ 執行查詢之前執行 ANALYZE 命令。
+ 在每個定期載入或更新週期結束時，例行地在資料庫上執行 ANALYZE 命令。
+ 在您建立的任何新資料表和經歷大幅變更的任何現有資料表或資料欄上執行 ANALYZE 命令。
+ 根據在查詢中的用途和變更的傾向，考慮以不同的排程為不同類型的資料表和資料欄執行 ANALYZE 操作。
+ 為了節省時間和叢集資源，執行 ANALYZE 時請使用 PREDICATE COLUMNS 子句。

將快照還原到佈建的叢集或無伺服器命名空間之後，以及在恢復暫停的佈建叢集之後，您都無須明確執行 ANALYZE 命令。在這些情況下，Amazon Redshift 會保留系統資料表資訊，因此不需要手動執行 ANALYZE 命令。Amazon Redshift 將根據需求繼續執行自動分析操作。

分析操作會略過有最新統計資訊的資料表。如果您在擷取、轉換和載入 (ETL) 工作流程中執行 ANALYZE，自動分析會略過有最新統計資訊的資料表。同樣地，當自動分析已更新資料表的統計資訊時，明確 ANALYZE 會略過資料表。

## ANALYZE 命令歷史記錄
<a name="c_check_last_analyze"></a>

知道上次對資料表或資料庫執行 ANALYZE 命令的時間很實用。執行 ANALYZE 命令時，Amazon Redshift 會執行看起來類似以下的多個查詢：

```
padb_fetch_sample: select * from table_name
```

查詢 STL\$1ANALYZE 來檢視分析操作的記錄。如果 Amazon Redshift 使用自動分析來分析資料表，`is_background` 欄會設為 `t` (true)。否則會設為 `f` (false)。下列範例聯結 STV\$1TBL\$1PERM，以顯示資料表名稱和執行期詳細資訊。

```
select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, a.starttime, a.endtime
from stl_analyze a 
join stv_tbl_perm t  on t.id=a.table_id
where name = 'users'
order by starttime;


xid    | name  | status          | rows  | modified_rows | starttime           | endtime            
-------+-------+-----------------+-------+---------------+---------------------+--------------------
  1582 | users | Full            | 49990 |         49990 | 2016-09-22 22:02:23 | 2016-09-22 22:02:28
244287 | users | Full            | 24992 |         74988 | 2016-10-04 22:50:58 | 2016-10-04 22:51:01
244712 | users | Full            | 49984 |         24992 | 2016-10-04 22:56:07 | 2016-10-04 22:56:07
245071 | users | Skipped         | 49984 |             0 | 2016-10-04 22:58:17 | 2016-10-04 22:58:17
245439 | users | Skipped         | 49984 |          1982 | 2016-10-04 23:00:13 | 2016-10-04 23:00:13
(5 rows)
```

或者，您可以執行更複雜的查詢，傳回在包括 ANALYZE 命令的每個完成的交易中執行的所有陳述式：

```
select xid, to_char(starttime, 'HH24:MM:SS.MS') as starttime,
datediff(sec,starttime,endtime ) as secs, substring(text, 1, 40)
from svl_statementtext
where sequence = 0
and xid in (select xid from svl_statementtext s where s.text like 'padb_fetch_sample%' )
order by xid desc, starttime;

xid  |  starttime   | secs |                  substring
-----+--------------+------+------------------------------------------
1338 | 12:04:28.511 |    4 | Analyze date
1338 | 12:04:28.511 |    1 | padb_fetch_sample: select count(*) from
1338 | 12:04:29.443 |    2 | padb_fetch_sample: select * from date
1338 | 12:04:31.456 |    1 | padb_fetch_sample: select * from date
1337 | 12:04:24.388 |    1 | padb_fetch_sample: select count(*) from
1337 | 12:04:24.388 |    4 | Analyze sales
1337 | 12:04:25.322 |    2 | padb_fetch_sample: select * from sales
1337 | 12:04:27.363 |    1 | padb_fetch_sample: select * from sales
...
```