Amazon Redshift Materialized Viewの自動更新を試してみた

# 背景・目的
Redshift Redshift Materialized Viewの自動更新を試してみたので整理します。

# まとめ
- Redshiftにも、RDBMSにあるようなMaterialized Viewがあります。
- リフレッシュの選択肢として、手動やスケジューラでコマンドによるリフレッシュもありますが、自動リフレッシュも利用できます。
- 自動リフレッシュを使用した場合に。おおよそ10秒程度でリフレッシュされました。
- 注意事項としては、自動更新よりもワークロードの優先順位を設定し、ユーザーのワークロードのパフォーマンスを維持するために自動更新を停止する場合があります。


# 概要
## マテリアライズドビューの自動更新
- Redshift は、自動更新オプションを使用してマテリアライズドビューを作成または変更すると、ベーステーブルの最新データでマテリアライズドビューを自動的に更新できます
- Redshift は、ベーステーブルが変更された後、できるだけ早くマテリアライズドビューを自動更新します。
- Redshift は自動更新よりもワークロードの優先順位を設定し、ユーザーのワークロードのパフォーマンスを維持するために自動更新を停止する場合があります。
    - このアプローチでは、一部のマテリアライズドビューの更新が遅れる可能性があります。場合によっては、マテリアライズドビューに対してより決定的な更新動作が必要になることがあります。
    - その場合は、REFRESH MATERIALIZED VIEWで説明されている手動更新、またはAmazon Redshift スケジューラ API オペレーションまたはコンソールを使用したスケジュール更新の使用を検討してください。


# 実装
今回は、Streaming Ingestionを使って自動リフレッシュを試します。

## KDSへのIngestionスクリプト
[こちら](https://qiita.com/zumax/items/92002a68d5be54e5d79f#%E5%AE%9F%E8%A1%8C)で作成したスクリプトを実行してKDSへIngestionします。

```
$ python3 stock.py
```

## Redshiftの設定
### Schemaを作成
```
CREATE EXTERNAL SCHEMA kds
FROM KINESIS
iam_role 'arn:aws:iam::{アカウントID}:role/{IAMロール}'

```

### Materialized Viewを作成
1. 上記のスキーマのKDSストリームを元にマテビューを作成します。
    - Createする際に、「AUTO REFRESH YES」を設定することでAuto Refresuが可能です。

    ```
    CREATE MATERIALIZED VIEW test.m_auto_mv_test AUTO REFRESH YES AS
    SELECT approximate_arrival_timestamp,
           JSON_PARSE(from_varbyte(kinesis_data, 'utf-8')) as Data
      FROM kds."Kinesisストリーム名"
     WHERE CAN_JSON_PARSE(kinesis_data);
    ```
1. マテビューを確認します。
    - autorefreshがtになっています。
    ```
    SELECT *
      FROM STV_MV_INFO
     WHERE schema = 'test'
    
    ====
    db_name schema name updated_upto_xid is_stale owner_user_name state autorefresh autorewrite
    sample	test	m_auto_mv_test	XXXXX	t	XXXXX	1	t	f
    ```

## リフレッシュの確認

1. マテビューのリフレッシュ状況（初期状態）を確認します。
    - 作成直後は12:49:01
    ```
    select * from SVL_MV_REFRESH_STATUS where mv_name ='m_auto_mv_test'
    
    ===
    
    db_name userid schema_name mv_name xid starttime endtime status refresh_type
    sample	100	test	m_auto_mv_test	5764861	2023-02-02 12:49:01.816306	2023-02-02 12:49:49.162186	Refresh successfully updated MV incrementally	Auto
    sample	100	test	m_auto_mv_test	5764919	2023-02-02 12:49:51.690503	2023-02-02 12:49:57.357026	Refresh successfully updated MV incrementally. Stream returned no new data	Auto
    ```

1. データのIngestionを開始します。
    ```
    $ python3 stock.py
    {'EVENT_TIME': '2023-02-02T13:17:58.712088', 'TICKER': 'MSFT', 'PRICE': 99.4}
    put success.
    {'EVENT_TIME': '2023-02-02T13:17:58.740720', 'TICKER': 'MSFT', 'PRICE': 71.36}
    put success.
    {'EVENT_TIME': '2023-02-02T13:17:58.749911', 'TICKER': 'MSFT', 'PRICE': 58.88}
    ```

1. リフレッシュ状況を確認（1回目）します。
    ```
    select GETDATE(), *  from SVL_MV_REFRESH_STATUS where mv_name ='m_auto_mv_test' order by starttime desc 
    
    ===
    getdate db_name userid schema_name mv_name xid starttime endtime status refresh_type
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767355	2023-02-02 13:20:56.936193	2023-02-02 13:21:02.5523	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767338	2023-02-02 13:20:48.922066	2023-02-02 13:20:54.717838	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767325	2023-02-02 13:20:40.917531	2023-02-02 13:20:46.710588	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767310	2023-02-02 13:20:32.910651	2023-02-02 13:20:38.590588	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767286	2023-02-02 13:20:24.899195	2023-02-02 13:20:30.709761	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767277	2023-02-02 13:20:16.895375	2023-02-02 13:20:22.727422	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767271	2023-02-02 13:20:08.890158	2023-02-02 13:20:14.536698	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767268	2023-02-02 13:20:00.886254	2023-02-02 13:20:06.621584	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767257	2023-02-02 13:19:52.873903	2023-02-02 13:19:58.621259	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:21:02	sample	100	test	m_auto_mv_test	5767235	2023-02-02 13:19:44.864274	2023-02-02 13:19:50.479814	Refresh successfully updated MV incrementally	Auto
    ```

1. リフレッシュ状況を確認（2回目）します。
    - endtimeの各レコードの感覚を確認したところ、おおよそ10秒程度でリフレッシュされているようです。
    ```
    select GETDATE(), *  from SVL_MV_REFRESH_STATUS where mv_name ='m_auto_mv_test' order by starttime desc 
    
    ===
    getdate db_name userid schema_name mv_name xid starttime endtime status refresh_type
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767489	2023-02-02 13:22:25.015362	2023-02-02 13:22:30.792514	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767480	2023-02-02 13:22:17.009913	2023-02-02 13:22:22.72585	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767474	2023-02-02 13:22:09.005866	2023-02-02 13:22:14.726162	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767453	2023-02-02 13:22:00.994914	2023-02-02 13:22:06.644877	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767450	2023-02-02 13:21:52.989857	2023-02-02 13:21:58.674165	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767427	2023-02-02 13:21:44.979723	2023-02-02 13:21:50.90783	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767419	2023-02-02 13:21:36.972704	2023-02-02 13:21:42.674697	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767390	2023-02-02 13:21:28.961068	2023-02-02 13:21:34.711305	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767381	2023-02-02 13:21:20.956939	2023-02-02 13:21:26.738792	Refresh successfully updated MV incrementally	Auto
    2023-02-02 13:22:32	sample	100	test	m_auto_mv_test	5767375	2023-02-02 13:21:12.951667	2023-02-02 13:21:18.581632	Refresh successfully updated MV incrementally	Auto
    ```

1. 到着したデータを確認します。
    - 参照した時刻（getdata）、Kinesisに到着した時刻（approximate_arrival_timestamp）、発生した時刻（EVENT_TIME）がほぼ同時刻である。
    - getdataと、approximate_arrival_timestampの差を見ると、15秒程度のタイムラグがあることが分かる。
    ```
      select GETDATE() , approximate_arrival_timestamp , data
        from test.m_auto_mv_test 
    order by approximate_arrival_timestamp desc 

    ===
    
    getdate approximate_arrival_timestamp data

    2023-02-02 13:31:29	2023-02-02 13:31:14.18	{"EVENT_TIME":"2023-02-02T13:31:14.175485","TICKER":"AMZN","PRICE":25.94}
    2023-02-02 13:31:29	2023-02-02 13:31:14.169	{"EVENT_TIME":"2023-02-02T13:31:14.165651","TICKER":"TBV","PRICE":67.62}
    2023-02-02 13:31:29	2023-02-02 13:31:14.16	{"EVENT_TIME":"2023-02-02T13:31:14.156076","TICKER":"TBV","PRICE":59.05}
    2023-02-02 13:31:29	2023-02-02 13:31:14.151	{"EVENT_TIME":"2023-02-02T13:31:14.146972","TICKER":"AAPL","PRICE":10.69}
    2023-02-02 13:31:29	2023-02-02 13:31:14.141	{"EVENT_TIME":"2023-02-02T13:31:14.135601","TICKER":"AMZN","PRICE":16.49}
    
    〜
    ```

# 考察
Auto Refreshを有効にすると15秒程度でリフレッシュされました。
ニアリアルタイムでデータが確認することができ、かつリフレッシュのオペレーションが不要です。
外部からリフレッシュする場合はスケジューラーでは、最低でも1分間隔となるためAuto Refreshは有用と感じました。
今後は、KDSに対して大量のデータをIngestionした場合でも、リフレッシュ間隔やリアルタイム性が変わらないか確認したいと想います。


# 参考

https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/materialized-view-refresh.html#materialized-view-auto-refresh

https://qiita.com/zumax/items/92002a68d5be54e5d79f

https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_STV_MV_INFO.html