【Redshift】データシェアリング越しにMviewを作成してみた

# 背景・目的
データシェアリングについて、データシェアリング越しにMaterialized Viewを作成し、Producerで更新したデータがConsumerで利用できるかを確認してみます。

# まとめ
データシェアリング越しにMviewの作成は可能でした。
ただし、データ共有されたオブジェクトは外部オブジェクトとして定義されるようで、[ドキュメント](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/materialized-view-refresh.html#materialized-view-auto-refresh)にあるように、外部テーブルとして定義されているMaterialized Viewは自動更新されないので、手動でリフレッシュする必要があります。

# 概要
データ共有の概要や特徴については、以前[こちら](https://qiita.com/zumax/items/555efda12bd1c3a65343)に纏めました。
あらためて、記載すると、下記のことが実現できます。
> データ共有を使用すると、Amazon Redshift クラスター間、AWSアカウント間、または AWS リージョン間で、読み取り目的でのライブデータの共有が比較的安全に、そして簡単に行えます。

下記の間のデータ共有が、読み取りのみライブデータ（リアルタイム）に「簡単」、「比較的安全」に行えるとのことでした。
- クラスタ間
- アカウント間
- リージョン間

また、データ共有により、下記の効果があります。
> データ共有により、組織の俊敏性が向上します。これは、Amazon Redshift クラスター全体にわたるデータに、詳細かつ高性能なアクセスが即座に行えるようにすることで実現します。手動でコピーまたは移動を実行する必要はありません。データ共有を使用すると、ユーザーはその時点のデータにアクセスできるため、Amazon Redshift クラスターで更新された最新情報を一貫して参照できます。

- データコピーや移動が不要（ETLなど不要）
- 最新（リアルタイム）データにアクセス可能

# 実践
今回は、下記のような構成で試してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/da549e5d-dd91-eef6-54f8-612c407da872.png)


- 背景色の説明は下記のとおりです。
    - 黄色がクラスタ
    - 赤がデータベース
    - 緑がスキーマ
    - 白がテーブル

## データの準備
まずは、Consumerに連携するにあたり、テーブルとデータを準備します。

::: note info
プロデューサー側の作業
:::


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/602ab424-4956-c171-7ba5-14ea67629805.png)


### テーブルの作成
ID列だけのテーブルを作成します。
```
CREATE TABLE producer.data_sharing_table_20230224 (id integer ENCODE az64) DISTSTYLE AUTO;
```

確認できました。
```
set search_path to '$user', public, producer;
select * from pg_table_def where tablename='data_sharing_table_20230224' 

===
schemaname	tablename	column	type	encoding	distkey	sortkey	notnull
producer	data_sharing_table_20230224	id	integer	az64	FALSE	0	FALSE

```

### 連携するデータを確認
```
SELECT * FROM producer.data_sharing_table_20230224
===
なし
```

## データシェアリングの設定
まずは、プロデューサー側でデータシェアリングの設定を作成します。

::: note info
プロデューサー側の作業
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/2ea55064-67fc-82a2-da59-337ff2967abf.png)



1. Redshiftのトップページから「データ共有」タブ＞「Create datashare」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/47c55a4e-7da6-aafe-b80d-e35baa9169f7.png)

1. Datashare informationで下記を入力します。
    - type : datashareを選択
    - データ共有名 ： ここではdatasharing_testとしました。
    - Database name : 作成したテーブルのデータベースを選択します。ここでは「dev」としました。
    - パブリックにアクセス可能 : Turn offとしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/d008f360-fa03-6b33-924a-c115b1bd418a.png)

1. データ共有オブジェクトを追加でかきを入力し、「追加」をクリックします。
    - スキーマ ： 作成したスキーマを選択
    - Object Types : テーブルとビューを選択
    - オブジェクトを追加 : Add specific objects from schemaを選択
    - テーブル名： 作成したテーブルを選択
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/2e53b174-dd4a-3945-12b5-aa6a7fdd9ff7.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/b814619b-9823-35e7-1693-14d79fbbd5b7.png)

1. Namespace IDsに連携先クラスタのnamespaceを選択し、「Create datashare」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/db2f5056-e44d-2b3c-00f2-fddcc06b483a.png)


1. Redshiftのデータ共有ページで「Shared」担っていることが確認できました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/58120fd1-126f-1a3b-858c-05ab587e9375.png)

### データ共有からデータベースを作成
プロデューサーで作成されたデータシェアリングを利用して、参照できるようにコンシューマ側で設定を行います。

::: note warn
コンシューマ側の作業
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/907bb876-304f-4401-0834-1f72deaa84f3.png)

1. データ共有タブで、プロデューサーで作成したデータ共有名が確認できますので、データ共有名をクリックします。(紛らわしいので、関係のないデータ共有名は網掛けにしています。) 
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/16991a9b-5689-8016-4be8-73bf35025e18.png)

1. 「データ共有からデータベースを作成」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/bb1a1f15-f3e4-8c97-024a-e76bc856f1d7.png)

1. 下記を入力し、「作成」をクリックします。
    - データ共有名
    - 名前空間
    - Database name : データシェアリングされたオブジェクトを参照するためのデータベースになります。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/45f74400-9b30-aaf7-aaf6-e0592258855c.png)

1. 作成されました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/b3e41521-899e-5bd9-22ae-ea932fc2cbcb.png)

1. クエリエディタでも確認ができました。SELECTしましたが、この時点ではデータゼロ件です。（想定通り。）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/04846de3-c942-6801-e423-f039072026f3.png)


## データ連携の確認
ここでは、Mviewを作成する前に、プロデューサーで登録したデータがコンシューマで参照できるか確認してみます。

### プロデューサーでデータを登録
::: note info
プロデューサー側の作業
:::

1. まずは一件登録します。
    ```
    INSERT INTO producer.data_sharing_table_20230224(id) VALUES(1);
    ```
1. プロデューサーで確認します。問題なく登録されています。
    ```
    SELECT * FROM producer.data_sharing_table_20230224
    ===
    id
    1
    ```

### プロデューサーで登録したデータをコンシューマーで確認
::: note warn
コンシューマ側の作業
:::
1. 確認できました。
    
    ```
    select * from producer_share.producer.data_sharing_table_20230224
    ===
    id
    1
    ```
## Materialized Viewの作成
::: note warn
コンシューマ側の作業
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ca6c3d69-a6ed-7e7e-1ad0-e74518b38d9e.png)


1. Materialized Viewを作成するスキーマを用意します。
    ```
    create schema mview;
    ```

1. Materialized Viewを作成します。
**外部テーブルで定義されているMaterialized viewは自動更新（Auto refresh 句をYes）にできません。**

    ```
    CREATE MATERIALIZED VIEW mview.m_id AS
    SELECT id FROM producer_share.producer.data_sharing_table_20230224
    ```

1. 条件付きでもう一つ作成します。
    ```
    CREATE MATERIALIZED VIEW mview.m_id AS
    SELECT id FROM producer_share.producer.data_sharing_table_20230224
    ```

1. 作成されたMviewを確認します。
    ```
    SELECT *
      FROM STV_MV_INFO
     WHERE schema = 'mview';
    
    ===
    db_name,schema,name,updated_upto_xid,is_stale,owner_user_name,state,autorefresh,autorewrite 
    "dev ","mview ","m_id_condition ",2211114,t,"XXX ",0,f,f 
    "dev ","mview ","m_id ",2210708,t,"XXX ",0,f,f
    
    ```

1. データを確認します。想定どおりです。
    ```
    SELECT * FROM mview.m_id;
    ===
    id
    1
    
    SELECT * FROM mview.m_id_condition;
    ===
    なし
    ```

## Materialized Viewへの反映の確認
### Producerのデータ登録
::: note info 
プロデューサー側の作業
::: 

1. データを新規に登録し確認します。
    ```
    INSERT INTO producer.data_sharing_table_20230224(id) VALUES(2);
    INSERT INTO producer.data_sharing_table_20230224(id) VALUES(10);
    
    SELECT * FROM producer.data_sharing_table_20230224
    
    ===
    id
    1
    2
    10
    
    ```

### Consumerのデータ確認
上記で登録したデータが参照できるか確認します。

::: note warn 
コンシューマー側の作業
::: 

1. まずは、リフレッシュする前の状態でSELECTしてみます。想定通り変わらずです。
    ```
    SELECT * FROM mview.m_id;
    ===
    id
    1
    
    SELECT * FROM mview.m_id_condition;
    ===
    なし
    ```


1. リフレッシュします。まずは条件なしMviewから実行します。参照できました。
    ```
    REFRESH MATERIALIZED VIEW mview.m_id;
    
    SELECT * FROM mview.m_id;
    ===
    id
    1
    2
    10
    ```

1. 次に条件ありMview（idが10のものだけ）をリフレッシュします。想定通り参照できました。
    ```
    SELECT * FROM mview.m_id_condition;
    ===
    id
    10ｋ
    ```

# 考察
データシェアリングされたデータに対して、すべてのデータは読み込まず、一部のデータを読み込みたい場合や、コンシューマー側で列名を変更した場合に、Materilized Viewが使えることがわかりました。（Viewでも実現可能かと思います。）
また、Materialized Viewのリフレッシュは自動リフレッシュが使用できないので、別途、アドホックまたは、スケジューラーに設定しRefreshコマンドを実行する用意が必要であることがわかりました。

# 参考
https://qiita.com/zumax/items/555efda12bd1c3a65343

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