LoginSignup
1
0

More than 3 years have passed since last update.

Redshiftで手動でAnalyzeを発行した方がよいケース

Posted at

はじめに

Redshiftにも他のDBMSと同様、統計情報を取得するためのAnalyzeコマンドがある。
ただ、AWSさんの「運用機能を可能な限り自動化し、開発者が本来注力すべき業務処理に注力できるように」との思いによって各種機能が年々Auto化(個人的には分散キーのAuto化が最後の砦だと思っていたので、去年のre:Inventはインパクトが大きかった)されたことで、Analyzeコマンドを発行する機会は減ってきていると思われる。
本記事では2021/4現在における自動で発行されるAnalyzeを整理するとともに、Analyzeを手動で発行した方がよいケースについて個人的な見解を整理する。

実機環境

リージョン:東京
インスタンス:dc2.large × 1ノード
※Redshiftのバージョンは2021/4/3時点での最新バージョンを使用

自動的に発行されるAnalyeze

Redshiftで自動的に発行されるAnalyzeには大きく2種類存在。
①コマンドとセットで発行されるAnalyze
②AutoAnalyze機能により発行されるAnalyze

コマンドとセットで発行されるAnalyze

Analyzeがセットで(自動的に)発行されるコマンドは下記4つ。
①COPY(STATUPDATEオプションとCOPY先テーブルのデータ状態により発行有無が変わる)
②CRETATE TALBE AS
③CREATE TEMP TABLE AS
④SELECT INTO
参考:Redshift開発者ガイド内「テーブルを分析する

また上記の派生として、下記コマンドについてもAnalyzeが発行される。
⑤CREATE MATERIALIZED VIEW
⑥REFRESH MATERIALIZED VIEW(増分更新の場合は発行されない)
※細かな挙動については記事の後半の「MATERIALIZED VIEWに関する挙動について」に記載

AutoAnalyze機能により発行されるAnalyze

COPYコマンドでtbl1テーブルにデータを格納し、AutoAnalyze機能の動きをSTL_ANALYZEテーブルから観察。

db1=# select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, CONVERT_TIMEZONE('JST',a.starttime) as starttime_j,is_auto,is_background,substring(auto_analyze_phase,1,20) from STL_ANALYZE a join stv_tbl_perm t on t.id=a.table_id order by starttime;
  xid  |  name  |     status      |   rows   | modified_rows |         starttime_j        | is_auto | is_background |      substring
-------+--------+-----------------+----------+---------------+----------------------------+---------+---------------+----------------------
  7027 | tbl1   | Full            | 20000000 |      20000000 | 2021-03-28 08:30:45.877363 | t       | f             | Not Applicable        ---COPYコマンドでデータをLoad
  7711 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 08:43:08.084746 | t       | t             | (Phase 1) Processing
  7711 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 08:43:08.085832 | t       | t             | (Phase 2) Processing
  7711 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 08:43:08.08619  | t       | t             | (Phase 3) Processing
 10959 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 09:43:09.346016 | t       | t             | (Phase 1) Processing
 10971 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 09:43:25.863039 | t       | t             | (Phase 2) Processing
 10971 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 09:43:25.863496 | t       | t             | (Phase 3) Processing
 14338 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 10:43:10.401768 | t       | t             | (Phase 1) Processing
 14351 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 10:43:20.258824 | t       | t             | (Phase 2) Processing
 14351 | tbl1   | Skipped         | 20000000 |             0 | 2021-03-28 10:43:20.259437 | t       | t             | (Phase 3) Processing

8時から10時の間だけではあるが、各時刻の43分にAutoAnalyzeが発行されており、おそらく1時間に1回のペースでAutoAnalyzeが稼働している模様。
上記ログはCOPYコマンド以降、当該テーブルにクエリを発行していないケースだが、別途COPYコマンド後にテーブルに更新クエリを発行するケースも試行したが1時間に1回のペースは変わらなかった。(ただ、数回程度の試行のためAutoAnalyzeが稼働するケースがある可能性はあり)

Analyzeを明示的に発行した方がよいケース

端的にまとめると「Analyzeが自動的に発行されないコマンドにより作成したテーブルを、1時間以内に参照し、かつ、統計情報が最新でないとパフォーマンスが出ないような参照クエリがある場合」。
(全然端的じゃない・・・)

基本的にRedshiftへ大量データを投入するときはCopyコマンド、CTASあたりかと思うが、他にあるとすればINSERT INTO SELECTでのデータ投入か。
※上記で記載した「SELECT INTO」とは別のコマンド。
※ISERT INTO SELECTでデータ投入した場合には、自動でAnalyzeが発行されないことも実機確認済み

MATERIALIZED VIEWに関する挙動について

以下の流れでコマンドを発行し、Analyze関連で内部的に発行されたコマンドをsvl_statementtextテーブルから、テーブルへのAnalyze実績をstl_analyzeテーブルから確認。
 ①tbl1にCOPYコマンドで3000万件をLoad
 ②CREATE MATERIALIZED VIEW
 ③tbl1にCOPYコマンドで2000万件を追加Load(STATUPDATEオプション設定無し)
 ④REFRESH MATERIALIZED VIEW(増分更新)
 ⑤tbl1にCOPYコマンドで2000万件を追加Load(STATUPDATEオプションON)
 ⑥tbl1をtruncata
 ⑦tbl1にCOPYコマンドで3000万件をLoad
 ⑧REFRESH MATERIALIZED VIEW(全量更新)

①tbl1にCOPYコマンドで3000万件をLoad

空テーブルに対しCOPYコマンドを発行するとセットでAnalyzeが発行される。

db1=# select xid, CONVERT_TIMEZONE('JST',starttime) as starttime,datediff(sec,starttime,endtime ) as secs, substring(text, 1, 300) 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,starttime;
 xid  |         starttime          | secs |                                                                                                substring
------+----------------------------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2616 | 2021-04-03 19:47:24.273663 |   64 | copy tbl1 from 's3://xxx';
 2616 | 2021-04-03 19:48:28.974304 |   20 | Analyze tbl1
 2616 | 2021-04-03 19:48:28.975073 |   14 | padb_fetch_sample: select * from tbl1
 2616 | 2021-04-03 19:48:42.26644  |    6 | padb_fetch_sample: select * from tbl1
 2616 | 2021-04-03 19:48:48.413595 |    0 | COMMIT

db1=# select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, CONVERT_TIMEZONE('JST',a.starttime) as starttime_j ,is_auto,is_background,substring(auto_analyze_phase,1,20) as phase from stl_analyze a join stv_tbl_perm t  on t.id=a.table_id order by starttime;
 xid  | name |     status      |   rows   | modified_rows |        starttime_j         | is_auto | is_background |     phase
------+------+-----------------+----------+---------------+----------------------------+---------+---------------+----------------
 2616 | tbl1 | Full            | 30000000 |      30000000 | 2021-04-03 19:48:28.974304 | t       | f             | Not Applicable

②CREATE MATERIALIZED VIEW

MATERIALIZED VIEWをCreateしたタイミングでAnalyzeコマンドが発行される。

db1=# select xid, CONVERT_TIMEZONE('JST',starttime) as starttime,datediff(sec,starttime,endtime ) as secs, substring(text, 1, 300) 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,starttime;
 xid  |         starttime          | secs |                                                                                                substring
------+----------------------------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2798 | 2021-04-03 19:50:50.25773  |   37 | Create MATERIALIZED VIEW mv_tbl1\nas select * from tbl1;
 2798 | 2021-04-03 19:51:27.151279 |    0 | Create MATERIALIZED VIEW mv_tbl1\nas select * from tbl1;
 2798 | 2021-04-03 19:51:27.15358  |    0 | Create MATERIALIZED VIEW mv_tbl1\nas select * from tbl1;
 2798 | 2021-04-03 19:51:27.165518 |   16 | Analyze mv_tbl__mv_tbl1__0
 2798 | 2021-04-03 19:51:27.165717 |   16 | padb_fetch_sample: select * from mv_tbl__mv_tbl1__0
 2798 | 2021-04-03 19:51:43.301068 |    0 | padb_fetch_sample: select * from mv_tbl__mv_tbl1__0
 2798 | 2021-04-03 19:51:43.847555 |    0 | COMMIT

db1=# select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, CONVERT_TIMEZONE('JST',a.starttime) as starttime_j ,is_auto,is_background,substring(auto_analyze_phase,1,20) as phase from stl_analyze a join stv_tbl_perm t  on t.id=a.table_id order by starttime;
 xid  |        name        |     status      |   rows   | modified_rows |        starttime_j         | is_auto | is_background |     phase
------+--------------------+-----------------+----------+---------------+----------------------------+---------+---------------+----------------
 2616 | tbl1               | Full            | 30000000 |      30000000 | 2021-04-03 19:48:28.974304 | t       | f             | Not Applicable
 2798 | mv_tbl__mv_tbl1__0 | Full            | 30000000 |             0 | 2021-04-03 19:51:27.165518 | t       | f             | Not Applicable

③tbl1にCOPYコマンドで2000万件をLoad(STATUPDATEオプション設定無し)

Analyzeの発行無し。
データ有りのテーブルにSTATUPDATEオプション無しでCOPYを実行した場合はAnalyzeは発行されない。

④REFRESH MATERIALIZED VIEW(増分更新)

Analyzeの発行無し。
増分更新の場合はAnalyzeは発行されない模様。
また、増分更新だったかどうかはリターンメッセージで確認可能。

db1=# REFRESH MATERIALIZED VIEW mv_tbl1;
INFO:  Materialized view mv_tbl1 was incrementally updated successfully.

ちなみに、全量更新の場合のメッセージは下記。

db1=# REFRESH MATERIALIZED VIEW mv_tbl1;
INFO:  Materialized view mv_tbl1 was recomputed successfully.

⑤tbl1にCOPYコマンドで2000万件をLoad(STATUPDATEオプションON)

STATUPDATEオプションONでCOPYコマンドを実行すると想定通りAnalyzeが自動で実行。

db1=# select xid, CONVERT_TIMEZONE('JST',starttime) as starttime,datediff(sec,starttime,endtime ) as secs, substring(text, 1, 300) 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,starttime;
 xid  |         starttime          | secs |                                                                                                substring
------+----------------------------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3503 | 2021-04-03 20:02:57.423461 |   46 | copy tbl1 from 's3://xxx';
 3503 | 2021-04-03 20:03:43.525802 |   33 | Analyze tbl1
 3503 | 2021-04-03 20:03:43.526022 |   28 | padb_fetch_sample: select * from tbl1
 3503 | 2021-04-03 20:04:11.532643 |    5 | padb_fetch_sample: select * from tbl1
 3503 | 2021-04-03 20:04:16.641362 |    0 | COMMIT

db1=# select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, CONVERT_TIMEZONE('JST',a.starttime) as starttime_j ,is_auto,is_background,substring(auto_analyze_phase,1,20) as phase from stl_analyze a join stv_tbl_perm t  on t.id=a.table_id order by starttime;
 xid  |        name        |     status      |   rows   | modified_rows |        starttime_j         | is_auto | is_background |     phase
------+--------------------+-----------------+----------+---------------+----------------------------+---------+---------------+----------------
 2616 | tbl1               | Full            | 30000000 |      30000000 | 2021-04-03 19:48:28.974304 | t       | f             | Not Applicable
 2798 | mv_tbl__mv_tbl1__0 | Full            | 30000000 |             0 | 2021-04-03 19:51:27.165518 | t       | f             | Not Applicable
 3503 | tbl1               | Full            | 70000000 |      40000000 | 2021-04-03 20:03:43.525802 | t       | f             | Not Applicable

⑥tbl1をtruncata

(MATERIALIZED VIEWを全量更新するため一度tbl1をtruncate)

⑦tbl1にCOPYコマンドで3000万件をLoad

再度、tbl1に3000万件を投入。

db1=# select xid, CONVERT_TIMEZONE('JST',starttime) as starttime,datediff(sec,starttime,endtime ) as secs, substring(text, 1, 300) 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,starttime;
 xid  |         starttime          | secs |                                                                                                substring
------+----------------------------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3782 | 2021-04-03 20:08:08.798301 |   60 | copy tbl1 from 's3://xxx';
 3782 | 2021-04-03 20:09:08.044916 |   12 | Analyze tbl1
 3782 | 2021-04-03 20:09:08.045211 |   10 | padb_fetch_sample: select * from tbl1
 3782 | 2021-04-03 20:09:18.211502 |    2 | padb_fetch_sample: select * from tbl1
 3782 | 2021-04-03 20:09:20.301491 |    0 | COMMIT

db1=# select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, CONVERT_TIMEZONE('JST',a.starttime) as starttime_j ,is_auto,is_background,substring(auto_analyze_phase,1,20) as phase from stl_analyze a join stv_tbl_perm t  on t.id=a.table_id order by starttime;
 xid  |        name        |     status      |   rows   | modified_rows |        starttime_j         | is_auto | is_background |     phase
------+--------------------+-----------------+----------+---------------+----------------------------+---------+---------------+----------------
 2616 | tbl1               | Full            | 30000000 |      30000000 | 2021-04-03 19:48:28.974304 | t       | f             | Not Applicable
 2798 | mv_tbl__mv_tbl1__0 | Full            | 30000000 |             0 | 2021-04-03 19:51:27.165518 | t       | f             | Not Applicable
 3503 | tbl1               | Full            | 70000000 |      40000000 | 2021-04-03 20:03:43.525802 | t       | f             | Not Applicable
 3782 | tbl1               | Full            | 30000000 |      30000000 | 2021-04-03 20:09:08.044916 | t       | f             | Not Applicable

⑧REFRESH MATERIALIZED VIEW(全量更新)

元テーブルがまるっと入れ替わった状態でREFRESHコマンドを発行すると、CTASで内部テーブルを作成し当該テーブルをMATERIALIZED VIEWに置き換えるような内部クエリが発行され、合わせてAnalyzeも発行。

db1=# select xid, CONVERT_TIMEZONE('JST',starttime) as starttime,datediff(sec,starttime,endtime ) as secs, substring(text, 1, 300) 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,starttime;
 xid  |         starttime          | secs |                                                                                                substring
------+----------------------------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3903 | 2021-04-03 20:10:24.456465 |   50 | REFRESH MATERIALIZED VIEW mv_tbl1;
 3903 | 2021-04-03 20:10:24.457537 |   50 | CALL public.mv_sp__mv_tbl1__0_1(0, 3902, 1, '(0)');
 3903 | 2021-04-03 20:10:24.46982  |   39 |  CREATE TABLE "public"."mv_tbl__mv_tbl1__0_recomputed" BACKUP YES DISTSTYLE KEY DISTKEY(2) COMPOUND SORTKEY(1, 2) AS (SELECT "tbl1".xxx
 3903 | 2021-04-03 20:11:03.50325  |   11 | Analyze mv_tbl__mv_tbl1__0_recomputed
 3903 | 2021-04-03 20:11:03.503481 |   11 | padb_fetch_sample: select * from mv_tbl__mv_tbl1__0_recomputed
 3903 | 2021-04-03 20:11:14.327198 |    0 | padb_fetch_sample: select * from mv_tbl__mv_tbl1__0_recomputed
 3903 | 2021-04-03 20:11:14.825666 |    0 | CREATE OR REPLACE VIEW "public"."mv_tbl1" AS (SELECT "derived_table1".xxx
 3903 | 2021-04-03 20:11:14.827848 |    0 | DROP TABLE "public"."mv_tbl__mv_tbl1__0"
 3903 | 2021-04-03 20:11:14.831234 |    0 | ALTER TABLE "public"."mv_tbl__mv_tbl1__0_recomputed" RENAME TO "mv_tbl__mv_tbl1__0"
 3903 | 2021-04-03 20:11:14.832263 |    0 | CREATE OR REPLACE VIEW "public"."mv_tbl1" AS (SELECT "derived_table1".xxx
 3903 | 2021-04-03 20:11:14.835738 |    0 | COMMIT

db1=# select distinct a.xid, trim(t.name) as name, a.status, a.rows, a.modified_rows, CONVERT_TIMEZONE('JST',a.starttime) as starttime_j ,is_auto,is_background,substring(auto_analyze_phase,1,20) as phase from stl_analyze a join stv_tbl_perm t  on t.id=a.table_id order by starttime;
 xid  |        name        |     status      |   rows   | modified_rows |        starttime_j         | is_auto | is_background |     phase
------+--------------------+-----------------+----------+---------------+----------------------------+---------+---------------+----------------
 2616 | tbl1               | Full            | 30000000 |      30000000 | 2021-04-03 19:48:28.974304 | t       | f             | Not Applicable
 3503 | tbl1               | Full            | 70000000 |      40000000 | 2021-04-03 20:03:43.525802 | t       | f             | Not Applicable
 3782 | tbl1               | Full            | 30000000 |      30000000 | 2021-04-03 20:09:08.044916 | t       | f             | Not Applicable
 3903 | mv_tbl__mv_tbl1__0 | Full            | 30000000 |             0 | 2021-04-03 20:11:03.50325  | t       | f             | Not Applicable

終わりに

記載が誤っている点や、わかりづらい点がありましたらコメントいただけますと幸いです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0