

 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_Distributing_data"></a>

當您將資料載入資料表時，Amazon Redshift 會根據資料表的分佈樣式，將資料表的資料列分佈至每一個運算節點。當您執行查詢時，查詢最佳化工具會視需要將資料列重新配送至運算節點，以執行任何聯結與彙總。選擇資料表配送樣式的目的是，藉由在執行查詢之前，將資料配置至必要的位置，以降低重新配送步驟所帶來的影響。

**注意**  
本節將向您介紹 Amazon Redshift 資料庫中資料分佈的原則。建議您使用 `DISTSTYLE AUTO` 建立資料表。如果您這樣做，Amazon Redshift 會使用自動資料表最佳化來選擇資料分發樣式。如需詳細資訊，請參閱[自動資料表最佳化](t_Creating_tables.md)。本節的其餘部分提供有關分佈樣式的詳細資料。

**Topics**
+ [資料分佈概念](#t_data_distribution_concepts)
+ [分佈樣式](c_choosing_dist_sort.md)
+ [檢視分佈樣式](viewing-distribution-styles.md)
+ [評估查詢模式](t_evaluating_query_patterns.md)
+ [指定分佈樣式](t_designating_distribution_styles.md)
+ [評估查詢計畫](c_data_redistribution.md)
+ [查詢計劃範例](t_explain_plan_example.md)
+ [分佈範例](c_Distribution_examples.md)

## 資料分佈概念
<a name="t_data_distribution_concepts"></a>

Amazon Redshift 的一些資料分佈概念如下。

 **節點和配量** 

 Amazon Redshift 叢集是一組節點。叢集中的每個節點都有自己的作業系統、專用的記憶體，以及專用的磁碟儲存空間。一個節點是*領導者節點*，其會管理運算節點的資料分佈和查詢處理任務。*運算節點*提供執行這些工作的資源。

 運算節點的磁碟儲存空間會分成一些*配量*。每一節點的配量數目取決於叢集的節點大小。節點全部會參與在執行的平行查詢中，以處理盡可能平均地分佈於配量的資料。如需每個節點大小有多少配量的相關資訊，請參閱《Amazon Redshift 管理指南》**中的[關於叢集和節點](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html#rs-about-clusters-and-nodes)。

 **資料重新分佈** 

 當您將資料載入資料表時，Amazon Redshift 會根據資料表的分佈樣式，將資料表的資料列分佈至每一個節點配量。做為查詢計畫的一部分，最佳化器會決定資料區塊需要位於何處，才能最佳地執行查詢。然後，系統會在查詢執行時實際移動或重新分配資料。重新分佈可能需要將特定資料列傳送至節點，以將整個資料表聯結或廣播至所有節點。

 資料重新分佈可以佔查詢計劃成本的很大一部分，並且它產生的網絡流量可能會影響其他資料庫操作，並降低整體系統效能。在某種程度上，您可以預期最初定位資料的最佳位置，將資料重新分佈的影響降至最低。

 **資料分佈目標** 

 當您將資料載入資料表時，Amazon Redshift 會根據您建立資料表時選擇的分佈樣式，將資料表的資料列分佈至運算節點及配量。資料分佈具有兩個主要目標：
+ 在叢集的節點之間平均分配工作負載。分佈不平均 (或資料分佈扭曲) 會迫使某些節點比其他節點更忙碌工作，導致查詢效能下降。
+ 為了盡量減少查詢執行時的資料移動。如果參與聯結或彙總的資料列已在其聯結資料列位於其他資料表的叢集上共置，則最佳化器不需要在查詢執行期間重新分佈儘可能多的資料。

您為資料庫選擇的分佈策略對查詢效能、儲存空間需求、資料載入和維護具有重要影響。藉由為每個資料表選擇最好的分佈樣式，您可以平衡資料分佈，並大幅改善整體系統效能。

# 分佈樣式
<a name="c_choosing_dist_sort"></a>

建立資料表時，您可以指定下列其中一種分佈樣式：AUTO、EVEN、KEY 或 ALL。

如果您不指定分佈樣式，Amazon Redshift 會使用 AUTO 分佈。

 **AUTO 分佈** 

使用 AUTO 分佈時，Amazon Redshift 會根據資料表資料的大小來指派最佳分佈樣式。例如，如果指定 AUTO 分佈樣式，Amazon Redshift 一開始會將 ALL 分佈樣式指派給小型資料表。當資料表變大時，Amazon Redshift 可能會將分佈樣式變更為 KEY，並選擇主索引鍵 (或複合主鍵的資料欄) 作為分佈索引鍵。如果資料表變大，並且沒有任何資料欄適合作為分佈索引鍵，則 Amazon Redshift 會將分佈樣式變更為 EVEN。分佈樣式的變更會發生在背景中，對使用者查詢的影響最小。

若要檢視 Amazon Redshift 自動執行的動作來修改資料表分佈索引鍵，請參閱 [SVL\$1AUTO\$1WORKER\$1ACTION](r_SVL_AUTO_WORKER_ACTION.md)。若要檢視有關修改資料表分佈索引鍵的目前建議，請參閱 [SVV\$1ALTER\$1TABLE\$1RECOMMENDATIONS](r_SVV_ALTER_TABLE_RECOMMENDATIONS.md)。

若要檢視套用至資料表的分佈樣式，請查詢 PG\$1CLASS\$1INFO 系統目錄檢視。如需詳細資訊，請參閱[檢視分佈樣式](viewing-distribution-styles.md)。如果您沒有以 CREATE TABLE 陳述式指定分佈樣式，Amazon Redshift 會套用 AUTO 分佈。

 **EVEN 分佈** 

 領導者節點會以循環模式在配量之間分佈資料列，而不考慮任何特定資料欄的值。當資料表不參與聯結時，EVEN 分佈是適當做法。當 KEY 分佈和 ALL 分佈之間沒有明確的選擇時，這也是合適的。

 **KEY 分佈** 

 資料列根據一個欄的值來分佈。領導節點會將相符的值放在相同的節點配量。如果您根據聯結索引鍵來分佈一對資料表，領導者節點會根據聯結欄的值將資料列共置在配量。這樣，來自共同資料欄的比對值會實際儲存在一起。

 **ALL 分佈** 

 整個資料表的副本分佈至每個節點。EVEN 分佈或 KEY 分佈只會將資料表的一部分資料列放在每個節點上，而 ALL 分佈可確保資料表參與的每個聯絡都共置每個資料列。

 ALL 分佈會增加叢集中節點數所需的儲存空間，因此需要更多時間來載入資料、更新資料，或將資料插入至多個資料表。ALL 分佈僅適用於移動速度相當緩慢的資料表，亦即，不經常或廣泛更新的資料表。因為在查詢期間重新分配小型資料表的成本很低，所以將小型維度資料表定義為 DISTSTYLE ALL 沒有顯著的優勢。

**注意**  
 指定資料欄的分佈樣式之後，Amazon Redshift 就會在叢集層級上處理資料分佈。Amazon Redshift 不需要或不支援在資料庫物件內分割資料的概念。您不需要建立資料表空間或定義資料表的分割方案。

在某些情況下，您可以在建立資料表的分佈樣式之後，變更該分佈樣式。如需詳細資訊，請參閱[ALTER TABLE](r_ALTER_TABLE.md)。對於建立資料表分佈樣式之後無法加以變更的情況，您可以重新建立資料表，並以深層複製填入新資料表。如需詳細資訊，請參閱[執行深層複製](performing-a-deep-copy.md)

# 檢視分佈樣式
<a name="viewing-distribution-styles"></a>

若要檢視資料表的分佈樣式，請查詢 PG\$1CLASS\$1INFO 檢視或 SVV\$1TABLE\$1INFO 檢視。

PG\$1CLASS\$1INFO 中的 RELEFFECTIVEDISTSTYLE 欄指出資料表的目前分佈樣式。如果資料表使用自動分佈，則 RELEFFECTIVEDISTSTYLE 為 10、11 或 12，這指出有效分佈樣式為 AUTO (ALL)、AUTO (EVEN) 或 AUTO (KEY)。如果資料表使用自動分布，則分佈樣式一開始可能顯示 AUTO (ALL)，然後在資料表變大時，變更為 AUTO (EVEN) 或 AUTO (KEY)。

下表提供 RELEFFECTIVEDISTSTYLE 欄中每個值的分佈樣式：


| RELEFFECTIVEDISTSTYLE | 目前分佈樣式 | 
| --- | --- | 
| 0 | EVEN | 
| 1 | KEY | 
| 8 | ALL | 
| 10 | AUTO (ALL) | 
| 11 | AUTO (EVEN) | 
| 12 | AUTO (KEY) | 

SVV\$1TABLE\$1INFO 中的 DISTSTYLE 欄指出資料表的目前分佈樣式。如果資料表使用自動分佈，則 DISTSTYLE 為 AUTO (ALL)、AUTO (EVEN) 或 AUTO (KEY)。

下列範例使用三個分佈樣式和自動分佈建立四個資料表，然後查詢 SVV\$1TABLE\$1INFO 來檢視分佈樣式。

```
create table public.dist_key (col1 int)
diststyle key distkey (col1);

insert into public.dist_key values (1);

create table public.dist_even (col1 int)
diststyle even;

insert into public.dist_even values (1);

create table public.dist_all (col1 int)
diststyle all;

insert into public.dist_all values (1);

create table public.dist_auto (col1 int);

insert into public.dist_auto values (1);

select "schema", "table", diststyle from SVV_TABLE_INFO
where "table" like 'dist%';

        schema   |    table        | diststyle
     ------------+-----------------+------------
      public     | dist_key        | KEY(col1)
      public     | dist_even       | EVEN
      public     | dist_all        | ALL
      public     | dist_auto       | AUTO(ALL)
```

# 評估查詢模式
<a name="t_evaluating_query_patterns"></a>

 選擇分佈樣式只是資料庫設計的一個環節。請在整個系統的內容中考慮分佈樣式，同時使用其他重要因素來平均分佈，例如叢集大小、壓縮編碼方法、排序索引鍵，以及資料表限制。

 利用儘可能接近真實資料的資料來測試您的系統。

若要為分佈樣式做出好選擇，您必須了解 Amazon Redshift 應用程式的查詢模式。識別系統中成本最高的查詢，並根據那些查詢的需求來設計初始的資料庫。決定查詢總成本的因素包括查詢執行所需的時間長度，以及耗用多少運算資源。決定查詢成本的其他因素是執行的頻率，以及對其他查詢和資料庫作業的干擾程度。

 識別成本最高查詢使用的資料表，並評估其在查詢執行期中的角色。請考慮聯結和彙總資料表的方式。

 使用本節中的準則來選擇每個資料表的分佈樣式。當您這樣做時，請建立資料表，並將儘可能接近真實資料的資料載入其中。然後測試資料表是否有您希望使用的查詢類型。您可以評估查詢解釋計畫來識別調校機會。比較載入時間、儲存空間和查詢執行期，以便平衡系統的整體需求。

# 指定分佈樣式
<a name="t_designating_distribution_styles"></a>

 本節中指定分佈樣式的考量和建議會使用星狀結構描述做為範例。您的資料庫設計可能根據星狀結構描述、某個星狀結構描述變體，或完全不同的結構描述。Amazon Redshift 會設計為可搭配您選擇的任何結構描述設計而有效運作。本節中的原理適用於任何設計結構描述。

1.  **指定您的所有資料表的主索引鍵和外部索引鍵。**

   Amazon Redshift 不會強制執行主索引鍵和外部索引鍵限制，但查詢最佳化器會在產生查詢計劃時使用這些限制。如果您設定主索引鍵和外部索引鍵，則您的應用程式必須維護索引鍵的有效性。

1.  **將事實資料表與其最大維度資料表配送至它們的通用欄位。**

   根據參與最常用聯結的資料集大小，而不只是資料表的大小來選擇最大維度。如果通常使用 WHERE 子句來篩選資料表，則只有其資料列的一部分參與聯結。這類資料表對重新分佈比提供更多資料的更小資料表具有更少的影響。將維度資料表的主索引鍵與事實資料表的對應外部索引鍵指定為 DISTKEY。如果多個資料表使用相同的分佈索引鍵，它們也將與事實資料表共置。您的事實資料表只能有一個分佈索引鍵。聯結其他索引鍵的任何資料表都不會與事實資料表共置。

1.  **指定其他維度資料表的分佈索引鍵。**

   根據其主索引鍵或外部索引鍵來分佈資料表，取決於它們最常與其他資料表聯結的方式。

1.  **評估是否將一些維度資料表變更為使用 ALL 分佈。**

   如果維度資料表無法與事實資料表或其他重要的聯結資料表共置，您可以藉由將整個資料表發佈至所有節點，以大幅提升查詢效能。使用 ALL 分佈會增加儲存空間要求，並增加載入時間與維護操作，因此在選擇 ALL 分佈之前，您應權衡所有因素。下節說明如何評估 EXPLAIN 計劃來識別 ALL 分佈的候選者。

1.  **對其餘資料表使用 AUTO 分佈。**

   如果資料表大部分去正規化且未參與聯結，或如果您未明確選擇另一個分佈樣式，請使用 AUTO 分佈。

若要讓 Amazon Redshift 選擇適當的分佈樣式，請不要明確指定分佈樣式。

# 評估查詢計畫
<a name="c_data_redistribution"></a>

您可以使用查詢計劃來識別可將分佈樣式最佳化的候選者。

在做出初始設計決策之後，請建立資料表、將資料載入其中，然後測試它們。使用儘可能接近真實資料的測試資料集。測量載入時間做為比較的基準。

評估哪些查詢代表您預期執行成本最高的查詢，尤指使用聯結和彙總的查詢。比較各種設計選項的執行期。比較執行期時，請不要將第一次執行查詢的時間列入計算，因為第一次執行期包含編譯時間。

**DS\$1DIST\$1NONE**  
不需要重新分佈，因為對應配量是在運算節點上共置。通常您將只有一個 DS\$1DIST\$1NONE 步驟，即事實資料表與某個維度資料表之間的聯結。

**DS\$1DIST\$1ALL\$1NONE**  
不需要重新分佈，因為內部資料表已使用 DISTSTYLE ALL。整個資料表位於每個節點上。

**DS\$1DIST\$1INNER**  
重新配送內部資料表。

**DS\$1DIST\$1OUTER**  
重新配送外部資料表。

**DS\$1BCAST\$1INNER**  
將整個內部資料表的副本播送至所有運算節點。

**DS\$1DIST\$1ALL\$1INNER**  
因為外部資料表使用 DISTSTYLE ALL，會將整個內部資料表重新配送至單一配量。

**DS\$1DIST\$1BOTH**  
重新配送這兩個資料表。

**DS\$1DIST\$1ERR**  
當資料表未選取分佈樣式時。

DS\$1DIST\$1NONE 和 DS\$1DIST\$1ALL\$1NONE 都是不錯的選擇。它們指出該步驟不需要重新分佈，因為所有聯結已共置。

DS\$1DIST\$1INNER 表示步驟將可能有相當高的成本，因為內部資料表正在重新分佈至節點。DS\$1DIST\$1INNER 指出外部資料表已適當地分佈在聯結索引鍵上。將內部資料表的分佈索引鍵設為聯結索引鍵，以將此項轉換為 DS\$1DIST\$1NONE。在某些情況下，無法在聯結索引鍵上分佈內部資料表，因為外部資料表不會在聯結索引鍵上分佈。如果是這種情況，請評估是否對內部資料表使用 ALL 分佈。如果資料表未經常或廣泛更新，而且大到足以帶來高重新分佈成本，請將分佈樣式變更為 ALL，然後重新測試。ALL 分佈會導致載入時間增加，因此當您重新測試時，請將載入時間併入您的評估因素中。

DS\$1DIST\$1ALL\$1INNER 不是好選擇。它表示整個內部資料表已重新分佈至單一配量，因為外部資料表使用 DISTSTYLE ALL，以便整個外部資料表的副本位於每個節點上。這會在單一節點上造成一連串無效的聯結執行期，而不是使用所有節點來善用平行執行期。DISTSTYLE ALL 主要只用於內部聯結資料表。反之，指定分佈索引鍵或甚至對外部資料表使用分佈。

DS\$1BCAST\$1INNER 和 DS\$1DIST\$1BOTH 不是好選擇。通常，這些重新分佈之所以發生，原因是未在資料表的分佈索引鍵上聯結資料表。如果事實資料表尚未有分佈索引鍵，請將聯結資料欄指定為這兩個資料表的分佈索引鍵。如果事實資料表已在另一個資料欄上具有分佈索引鍵，則請評估變更分佈索引鍵來共置此聯結是否將改善整體效能。如果變更外部資料表的分佈索引鍵不是最佳選擇，則您可以對內部資料表指定 DISTSTYLE ALL 來實現共置。

 下列範例顯示具有 DS\$1BCAST\$1INNER 和 DS\$1DIST\$1NONE 標籤之查詢計劃的一部分。

```
->  XN Hash Join DS_BCAST_INNER  (cost=112.50..3272334142.59 rows=170771 width=84)
        Hash Cond: ("outer".venueid = "inner".venueid)
        ->  XN Hash Join DS_BCAST_INNER  (cost=109.98..3167290276.71 rows=172456 width=47)
              Hash Cond: ("outer".eventid = "inner".eventid)
              ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
                    Merge Cond: ("outer".listid = "inner".listid)
                    ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
                    ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
```

在變更維度資料表來使用 DISTSTYLE ALL 之後，相同查詢的查詢計劃便會顯示 DS\$1DIST\$1ALL\$1NONE 代替 DS\$1BCAST\$1INNER。另外，聯結步驟的相對成本會發生大幅變更。與之前查詢中的 `3272334142.59` 相比，總成本是 `14142.59`。

```
->  XN Hash Join DS_DIST_ALL_NONE  (cost=112.50..14142.59 rows=170771 width=84)
        Hash Cond: ("outer".venueid = "inner".venueid)
        ->  XN Hash Join DS_DIST_ALL_NONE  (cost=109.98..10276.71 rows=172456 width=47)
              Hash Cond: ("outer".eventid = "inner".eventid)
              ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
                    Merge Cond: ("outer".listid = "inner".listid)
                    ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
                    ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
```

# 查詢計劃範例
<a name="t_explain_plan_example"></a>

此範例顯示如何評估查詢計劃來找出最佳化分佈的機會。

搭配 EXPLAIN 命令執行下列查詢來產生查詢計劃。

```
explain
select lastname, catname, venuename, venuecity, venuestate, eventname, 
month, sum(pricepaid) as buyercost, max(totalprice) as maxtotalprice
from category join event on category.catid = event.catid
join venue on venue.venueid = event.venueid
join sales on sales.eventid = event.eventid
join listing on sales.listid = listing.listid
join date on sales.dateid = date.dateid
join users on users.userid = sales.buyerid
group by lastname, catname, venuename, venuecity, venuestate, eventname, month
having sum(pricepaid)>9999
order by catname, buyercost desc;
```

在 TICKIT 資料庫中，SALES 是事實資料表，而 LISTING 是最大維度。為了共置資料表，SALES 會分佈在 LISTID (即 LISTING 的外部索引鍵) 上，而 LISTING 會分佈在其主索引鍵 LISTID 上。下列範例顯示 SALES 和 LISTING 的 CREATE TABLE 命令。

```
create table sales(
	salesid integer not null,
	listid integer not null distkey,
	sellerid integer not null,
	buyerid integer not null,
	eventid integer not null encode mostly16,
	dateid smallint not null,
	qtysold smallint not null encode mostly8,
	pricepaid decimal(8,2) encode delta32k,
	commission decimal(8,2) encode delta32k,
	saletime timestamp,
	primary key(salesid),
	foreign key(listid) references listing(listid),
	foreign key(sellerid) references users(userid),
	foreign key(buyerid) references users(userid),
	foreign key(dateid) references date(dateid))
        sortkey(listid,sellerid);

create table listing(
	listid integer not null distkey sortkey,
	sellerid integer not null,
	eventid integer not null encode mostly16,
	dateid smallint not null,
	numtickets smallint not null encode mostly8,
	priceperticket decimal(8,2) encode bytedict,
	totalprice decimal(8,2) encode mostly32,
	listtime timestamp,
	primary key(listid),
	foreign key(sellerid) references users(userid),
	foreign key(eventid) references event(eventid),
	foreign key(dateid) references date(dateid));
```

在下列查詢計劃中，SALES 和 LISTING 上聯結的合併聯結步驟顯示 DS\$1DIST\$1NONE，這指出步驟不需要重新分佈。不過，往上移動查詢計劃時，其他內部資料表顯示 DS\$1BCAST\$1INNER，這指出內部資料表將播送，做為查詢執行的一部分。因為只有一對資料表可以使用索引鍵分佈來進行共置，所以五個資料表必須重新播送。

```
QUERY PLAN
XN Merge  (cost=1015345167117.54..1015345167544.46 rows=1000 width=103)
  Merge Key: category.catname, sum(sales.pricepaid)
  ->  XN Network  (cost=1015345167117.54..1015345167544.46 rows=170771 width=103)
        Send to leader
        ->  XN Sort  (cost=1015345167117.54..1015345167544.46 rows=170771 width=103)
              Sort Key: category.catname, sum(sales.pricepaid)
              ->  XN HashAggregate  (cost=15345150568.37..15345152276.08 rows=170771 width=103)
                    Filter: (sum(pricepaid) > 9999.00)
	                    ->  XN Hash Join DS_BCAST_INNER  (cost=742.08..15345146299.10 rows=170771 width=103)
	                          Hash Cond: ("outer".catid = "inner".catid)
	                          ->  XN Hash Join DS_BCAST_INNER  (cost=741.94..15342942456.61 rows=170771 width=97)
	                                Hash Cond: ("outer".dateid = "inner".dateid)
	                                ->  XN Hash Join DS_BCAST_INNER  (cost=737.38..15269938609.81 rows=170766 width=90)
	                                      Hash Cond: ("outer".buyerid = "inner".userid)
	                                      ->  XN Hash Join DS_BCAST_INNER  (cost=112.50..3272334142.59 rows=170771 width=84)
	                                            Hash Cond: ("outer".venueid = "inner".venueid)
	                                            ->  XN Hash Join DS_BCAST_INNER  (cost=109.98..3167290276.71 rows=172456 width=47)
	                                                  Hash Cond: ("outer".eventid = "inner".eventid)
	                                                  ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
	                                                        Merge Cond: ("outer".listid = "inner".listid)
	                                                        ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
	                                                        ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
	                                                  ->  XN Hash  (cost=87.98..87.98 rows=8798 width=25)
	                                                        ->  XN Seq Scan on event  (cost=0.00..87.98 rows=8798 width=25)
	                                            ->  XN Hash  (cost=2.02..2.02 rows=202 width=41)
	                                                  ->  XN Seq Scan on venue  (cost=0.00..2.02 rows=202 width=41)
	                                      ->  XN Hash  (cost=499.90..499.90 rows=49990 width=14)
	                                            ->  XN Seq Scan on users  (cost=0.00..499.90 rows=49990 width=14)
	                                ->  XN Hash  (cost=3.65..3.65 rows=365 width=11)
	                                      ->  XN Seq Scan on date  (cost=0.00..3.65 rows=365 width=11)
	                          ->  XN Hash  (cost=0.11..0.11 rows=11 width=10)
	                                ->  XN Seq Scan on category  (cost=0.00..0.11 rows=11 width=10)
```

一種解決方案是將資料表修改為具有 DISTSTYLE ALL。

```
ALTER TABLE users ALTER DISTSTYLE ALL;
ALTER TABLE venue ALTER DISTSTYLE ALL;
ALTER TABLE category ALTER DISTSTYLE ALL;
ALTER TABLE date ALTER DISTSTYLE ALL;
ALTER TABLE event ALTER DISTSTYLE ALL;
```

再次搭配 EXPLAIN 執行相同的查詢，並檢查新的查詢計劃。聯結現在會顯示 DS\$1DIST\$1ALL\$1NONE，指出不需要重新分佈，因為已使用 DISTSTYLE ALL 將資料分佈至每一個節點。

```
QUERY PLAN
XN Merge  (cost=1000000047117.54..1000000047544.46 rows=1000 width=103)
  Merge Key: category.catname, sum(sales.pricepaid)
  ->  XN Network  (cost=1000000047117.54..1000000047544.46 rows=170771 width=103)
        Send to leader
        ->  XN Sort  (cost=1000000047117.54..1000000047544.46 rows=170771 width=103)
              Sort Key: category.catname, sum(sales.pricepaid)
              ->  XN HashAggregate  (cost=30568.37..32276.08 rows=170771 width=103)
                    Filter: (sum(pricepaid) > 9999.00)
                    ->  XN Hash Join DS_DIST_ALL_NONE  (cost=742.08..26299.10 rows=170771 width=103)
                          Hash Cond: ("outer".buyerid = "inner".userid)
                          ->  XN Hash Join DS_DIST_ALL_NONE  (cost=117.20..21831.99 rows=170766 width=97)
                                Hash Cond: ("outer".dateid = "inner".dateid)
                                ->  XN Hash Join DS_DIST_ALL_NONE  (cost=112.64..17985.08 rows=170771 width=90)
                                      Hash Cond: ("outer".catid = "inner".catid)
                                      ->  XN Hash Join DS_DIST_ALL_NONE  (cost=112.50..14142.59 rows=170771 width=84)
                                            Hash Cond: ("outer".venueid = "inner".venueid)
                                            ->  XN Hash Join DS_DIST_ALL_NONE  (cost=109.98..10276.71 rows=172456 width=47)
                                                  Hash Cond: ("outer".eventid = "inner".eventid)
                                                  ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
                                                        Merge Cond: ("outer".listid = "inner".listid)
                                                        ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
                                                        ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
                                                  ->  XN Hash  (cost=87.98..87.98 rows=8798 width=25)
                                                        ->  XN Seq Scan on event  (cost=0.00..87.98 rows=8798 width=25)
                                            ->  XN Hash  (cost=2.02..2.02 rows=202 width=41)
                                                  ->  XN Seq Scan on venue  (cost=0.00..2.02 rows=202 width=41)
                                      ->  XN Hash  (cost=0.11..0.11 rows=11 width=10)
                                            ->  XN Seq Scan on category  (cost=0.00..0.11 rows=11 width=10)
                                ->  XN Hash  (cost=3.65..3.65 rows=365 width=11)
                                      ->  XN Seq Scan on date  (cost=0.00..3.65 rows=365 width=11)
                          ->  XN Hash  (cost=499.90..499.90 rows=49990 width=14)
                                ->  XN Seq Scan on users  (cost=0.00..499.90 rows=49990 width=14)
```

# 分佈範例
<a name="c_Distribution_examples"></a>

下列範例顯示如何根據您在 CREATE TABLE 陳述式中定義的選項來分佈資料。

## DISTKEY 範例
<a name="c_Distribution_examples-distkey-examples"></a>

查看 TICKIT 資料庫中 USERS 資料表的結構描述。USERID 會定義為 SORTKEY 資料欄和 DISTKEY 資料欄：

```
select "column", type, encoding, distkey, sortkey 
from pg_table_def where tablename = 'users';
    
    column     |          type          | encoding | distkey | sortkey
---------------+------------------------+----------+---------+---------
 userid        | integer                | none     | t       |       1
 username      | character(8)           | none     | f       |       0
 firstname     | character varying(30)  | text32k  | f       |       0

...
```

USERID 是此資料表上分佈資料欄不錯的選擇。如果查詢 SVV\$1DISKUSAGE 系統檢視，您可以看到資料表很均勻地分佈。資料欄號碼以零開始，所以 USERID 為資料欄 0。

```
select slice, col, num_values as rows, minvalue, maxvalue
from svv_diskusage
where name='users' and col=0 and rows>0
order by slice, col;

slice| col | rows  | minvalue | maxvalue
-----+-----+-------+----------+----------
0    | 0   | 12496 | 4        | 49987
1    | 0   | 12498 | 1        | 49988
2    | 0   | 12497 | 2        | 49989
3    | 0   | 12499 | 3        | 49990
(4 rows)
```

資料表包含 49,990 個資料列。資料列 (num\$1values) 資料欄顯示每個配量包含大約相同數目的資料列。minvalue 和 maxvalue 資料欄顯示每一個配量上的值範圍。每一個配量幾乎包含整個值範圍，所以每一個配量都有很好的機會參與執行一個篩選使用者 ID 範圍的查詢。

此範例示範小型測試系統上的分佈。配量總數通常高得多。

如果您最常使用 STATE 資料欄進行聯結或分組，則可以選擇在 STATE 資料欄上進行分佈。下列範例顯示，若您建立一個新資料表，其中資料與 USERS 資料表相同，但將 DISTKEY 設為 STATE 資料欄。在此情況下，分佈不是平均的。配量 0 (13,587 個資料列) 比配量 3 (10,150 個資料列) 多保留大約 30% 的資料列。在規模很大的資料表中，此分佈扭曲數量可能對查詢處理具有負面影響。

```
create table userskey distkey(state) as select * from users;

select slice, col, num_values as rows, minvalue, maxvalue from svv_diskusage
where name = 'userskey' and col=0 and rows>0
order by slice, col;

slice | col | rows  | minvalue | maxvalue
------+-----+-------+----------+----------
    0 |   0 | 13587 |        5 |    49989
    1 |   0 | 11245 |        2 |    49990
    2 |   0 | 15008 |        1 |    49976
    3 |   0 | 10150 |        4 |    49986
(4 rows)
```

## DISTSTYLE EVEN 範例
<a name="c_Distribution_examples-diststyle-even-example"></a>

如果您建立一個新資料表，其中資料與 USERS 資料表相同，但將 DISTSTYLE 設為 EVEN，則資料列一律平均地分佈在配量上。

```
create table userseven diststyle even as 
select * from users;

select slice, col, num_values as rows, minvalue, maxvalue from svv_diskusage
where name = 'userseven' and col=0 and rows>0
order by slice, col;

slice | col | rows  | minvalue | maxvalue
------+-----+-------+----------+----------
    0 |   0 | 12497 |        4 |    49990
    1 |   0 | 12498 |        8 |    49984
    2 |   0 | 12498 |        2 |    49988
    3 |   0 | 12497 |        1 |    49989  
(4 rows)
```

不過，因為分佈不是根據特定資料欄，所以查詢處理能力可能降低，尤其在資料表聯結至其他資料表時更是如此。聯結資料欄若少了分佈，通常會影響可以有效地執行聯結操作的類型。當這兩個資料表在其各自聯結資料欄上進行分佈和排序時，會最佳化聯結、彙總和分組操作。

## DISTSTYLE ALL 範例
<a name="c_Distribution_examples-diststyle-all-example"></a>

如果您建立一個新資料表，其中資料與 USERS 資料表相同，但將 DISTSTYLE 設為 ALL，則所有資料列會分佈至每個節點的第一個配量。

```
select slice, col, num_values as rows, minvalue, maxvalue from svv_diskusage
where name = 'usersall' and col=0 and rows > 0
order by slice, col;

slice | col | rows  | minvalue | maxvalue
------+-----+-------+----------+----------
    0 |   0 | 49990 |        4 |    49990
    2 |   0 | 49990 |        2 |    49990

(4 rows)
```