本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
分析資料表
ANALYZE 操作會更新查詢規劃器用來選擇最佳計劃的統計中繼資料。
在大多數情況下,您不需要明確執行 ANALYZE命令。Amazon Redshift 會監控工作負載的變更,並在背景自動更新統計資料。此外,COPY命令會在將資料載入空白資料表時自動執行分析。
若要明確分析資料表或整個資料庫,請執行 ANALYZE 命令。
自動分析
Amazon Redshift 會持續監控資料庫,並自動在背景中執行分析操作。為了盡量減少對系統效能的影響,自動分析會在工作負載較低期間執行。
預設會啟用自動分析。若要關閉自動分析,請修改叢集的參數群組,將 auto_analyze
參數設為 false
。
為了減少處理時間並提高整體系統效能,對於修改程度較小的任何資料表,Amazon Redshift 會略過自動分析。
分析操作會略過具有 up-to-date統計資料的資料表。如果您在擷取、轉換和載入 (ETL) 工作流程中ANALYZE執行 ,自動分析會略過具有目前統計資料的資料表。同樣地,當自動分析更新了資料表的統計資料時,明確會ANALYZE略過資料表。
新資料表資料的分析
根據預設,COPY命令會在將資料載入空白資料表ANALYZE後執行 。無論資料表ANALYZE是否空白,您都可以透過設定 STATUPDATE ON 強制 。如果您指定 STATUPDATE OFF,ANALYZE則不會執行 。只有資料表擁有者或超級使用者可以執行ANALYZE命令,或使用STATUPDATE設定為 ON 的COPY命令執行命令。
Amazon Redshift 也會分析您使用下列命令建立的新資料表:
-
CREATE TABLE AS (CTAS)
-
CREATE TEMP TABLE AS
-
SELECT INTO
對最初載入資料後未分析的新資料表執行查詢時,Amazon Redshift 會傳回警告訊息。在後續更新或載入之後查詢資料表時不會發生警告。當您在參考尚未分析之資料表的查詢上執行EXPLAIN命令時,會傳回相同的警告訊息。
每當將資料新增至非空白資料表就會大幅改變資料表大小時,您可以明確更新統計資訊。您可以執行 ANALYZE 命令,或將 STATUPDATE ON 選項與 COPY命令搭配使用,藉此執行此操作。若要檢視自上次 以來已插入或刪除的資料列數目的詳細資訊ANALYZE,請查詢PG_STATISTIC_INDICATOR系統目錄表。
您可以將 ANALYZE 命令的範圍指定為下列其中一項:
-
整個目前資料庫
-
單一資料表
-
單一資料表中的一或多個特定資料欄
-
可能用作查詢中述詞的資料欄
ANALYZE 命令會從資料表取得資料列範例、執行一些計算,並儲存產生的資料欄統計資料。依預設,Amazon Redshift 會為 DISTKEY 資料欄執行範例傳遞,而另一個範例傳遞則會為資料表中的所有其他資料欄執行。如果您想要為資料欄的子集產生統計資料,您可以指定以逗點分隔的資料欄清單。您可以使用 ANALYZE PREDICATECOLUMNS子句執行,略過不用作述詞的資料欄。
ANALYZE 操作是資源密集的,因此僅在實際上需要統計資料更新的資料表和資料欄上執行它們。您不需要經常或按相同的排程分析所有資料表中的所有資料欄。如果資料本質上變更,請分析在下列項目中經常使用的資料欄:
-
排序和群組操作
-
聯結
-
查詢述詞
為了縮短處理時間並改善整體系統效能,Amazon Redshift ANALYZE會略過任何變更資料列百分比較低的資料表,如 analyze_threshold_percent 參數所決定。依預設,分析閾值是設為 10%。您可以執行 SET 命令來變更目前工作階段的分析閾值。
較不需要頻繁分析的欄是代表事實和指標的欄,以及從未實際查詢過的任何相關屬性,例如大型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);
假設應用程式中的賣家和事件更為靜態,且日期IDs是指僅涵蓋兩到三年的固定天數。在此情況下,這些欄的唯一值不會大幅變更。不過,每個唯一值的執行個體數目將會穩定增加。
此外,請考慮與資料TOTALPRICE欄相比,不常查詢 NUMTICKETS和 PRICEPERTICKET量值的情況。在此情況下,您可以每週末在整資料表上執行一次 ANALYZE 命令,以更新未每天分析的五個資料欄的統計資料:
述詞欄位
做為指定資料欄清單的便利替代方案,您可以選擇僅分析可能用來作為述詞的資料列。執行查詢時,在聯結中使用的任何資料欄、篩選條件或群組依據子句會在系統目錄中標示為述詞資料欄。當您ANALYZE使用 PREDICATECOLUMNS子句執行 時,分析操作只會包含符合下列條件的資料欄:
-
此資料欄已標示為述詞資料欄。
-
資料欄是分佈索引鍵。
-
資料欄是排序索引鍵的一部分。
如果資料表的任何資料欄都未標示為述詞,即使PREDICATECOLUMNS已指定 , 也會ANALYZE包含所有資料欄。如果沒有資料欄已標示為述詞資料欄,可能是因為尚未查詢該資料表。
當您工作負載的查詢模式相對穩定PREDICATECOLUMNS時,您可以選擇使用 。當查詢模式為可變模式時,使用 時,使用 經常使用不同的資料欄作為述詞,PREDICATECOLUMNS可能會暫時導致過時的統計資料。過時的統計資料可能導致次佳的查詢執行期計劃和較長的執行期。不過,下次ANALYZE使用 PREDICATE 執行 時COLUMNS,會包含新的述詞欄。
若要檢視述詞資料欄的詳細資訊,請使用下列項目SQL建立名為 PREDICATE_ 的檢視COLUMNS。
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_COLUMNS 檢視時,如下列範例所示,您會看到 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操作,取決於它們在查詢中的使用及其變更的傾向。
-
若要節省時間和叢集資源,請在執行 時使用 PREDICATECOLUMNS子句ANALYZE。
在將快照還原至佈建的叢集或無伺服器命名空間之後,或繼續暫停的佈建叢集之後,您不需要明確執行ANALYZE命令。Amazon Redshift 會在這些情況下保留系統資料表資訊,因此不需要手動ANALYZE命令。Amazon Redshift 將根據需求繼續執行自動分析操作。
分析操作會略過具有 up-to-date統計資料的資料表。如果您在擷取、轉換和載入 (ETL) 工作流程中ANALYZE執行 ,自動分析會略過具有目前統計資料的資料表。同樣地,當自動分析更新了資料表的統計資料時,明確會ANALYZE略過資料表。
ANALYZE 命令歷史記錄
知道資料表或資料庫上上次執行ANALYZE命令的時間很有用。執行ANALYZE命令時,Amazon Redshift 會執行多個如下所示的查詢:
padb_fetch_sample: select * from table_name
查詢 STL_ANALYZE 以檢視分析操作的歷史記錄。如果 Amazon Redshift 使用自動分析來分析資料表,is_background
欄會設為 t
(true)。否則會設為 f
(false)。下列範例會加入 STV_TBL_PERM 以顯示資料表名稱和執行期詳細資訊。
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 ...