[アップデート] Amazon Redshift のシステムテーブルを Amazon S3 Tables に自動配信できるようになったので試してみた

[アップデート] Amazon Redshift のシステムテーブルを Amazon S3 Tables に自動配信できるようになったので試してみた

Amazon Redshift のシステムテーブルを S3 に長期保持できる新機能「System table integration with S3 Tables」を、Amazon Redshift Serverless で実際に試してみました。
2026.08.21

クラウド事業統括本部の石川です。Amazon Redshift と Amazon Redshift Serverless のシステムテーブルを Amazon S3 Tables に長期保持できる「System table integration with S3 Tables」が利用可能になりましたので、Amazon Redshift Serverless で実際に試してみました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/08/redshift-long-term-system-table-retention/

先日、APIのアップデートが先に出ていたのでAPIで検証を先に進めていました。後日、マネジメントコンソールによる構築を紹介するように変更しようとも考えましたが、本番運用においては内部的な仕組みの理解が欠かせないと考えたため、AWSCLIを中心に解説します。

https://awsapichanges.com/archive/changes/4429ee-redshift-serverless.html

Amazon Redshift のシステムテーブルとは

Amazon Redshift は、クエリの実行履歴・接続履歴・自動最適化の実行結果といった運用情報を SYS_* というモニタリングビューで公開しています。プロビジョンドクラスターと Amazon Redshift Serverless の両方で利用でき、性能分析やトラブルシューティングの起点になる情報源です。

ただし、これらのデータはデータウェアハウス内に 7 日間しか保持されません。それ以上の期間を分析したい場合、これまでは UNLOAD などで退避する独自の仕組みを別途構築する必要がありました。

アップデート内容

今回のアップデートにより、選択した SYS_* システムテーブルのデータを Amazon Redshift が自動的に Amazon S3 Tables へ配信できるようになりました。

主な変更点は以下のとおりです。

  • 既存のログ関連 API に s3table という新しいログ出力先(log destination type)が追加された
  • 有効化すると、Amazon Redshift がアカウント内に aws-redshift という名前の S3 テーブルバケットを自動作成する
  • S3 テーブルバケット・ネームスペース・テーブルの作成、スキーマの定義と進化、Apache Iceberg 形式での書き込み、コンパクション、スナップショット管理まで AWS 側が実施する(サービス管理型)
  • 構築・保守するインフラストラクチャがなく、既存ワークロードへの影響もない
  • データは一定の頻度でバッチ配信され、各レコードは 1 回だけ配信される(exactly-once)
  • 最終状態に達したレコードのみが配信される(実行中のクエリは、完了・中断・キャンセルなどの最終状態になるまで配信されない)
  • 配信されたデータはイミュータブルで、Amazon Redshift 経由で行の変更・削除はできない

公式ドキュメントでは、想定ユースケースとして以下が挙げられています。

  • コンプライアンス・監査要件への対応: クエリ履歴、接続履歴、変更履歴を数か月から数年単位で保持する
  • フリート全体の一元監視: 同一アカウント・同一リージョン内の複数データウェアハウスの監視データを集約して横断分析する
  • 独自 ETL パイプラインの廃止: 長期保持のためにシステムテーブルを S3 へエクスポートするジョブの構築・保守をやめる
  • 過去インシデントの調査: 7 日間のウィンドウを超えた履歴データを使って、根本原因分析や事後レビュー、ワークロードの推移分析を行う

対応するシステムテーブル

配信対象として選択できるのは、以下の 28 個の SYS_* モニタリングビューです。

SYS_ANALYZE_COMPRESSION_HISTORY / SYS_ANALYZE_HISTORY / SYS_AUTOMATIC_OPTIMIZATION / SYS_AUTO_TABLE_OPTIMIZATION / SYS_CHILD_QUERY_TEXT / SYS_CONNECTION_LOG / SYS_COPY_JOB_INFO / SYS_COPY_REPLACEMENTS / SYS_DATASHARE_CHANGE_LOG / SYS_DATASHARE_USAGE_CONSUMER / SYS_DATASHARE_USAGE_PRODUCER / SYS_DATASHARE_WRITE_HISTORY / SYS_EXTERNAL_QUERY_ERROR / SYS_INTEGRATION_ACTIVITY / SYS_MV_STATE / SYS_PROCEDURE_MESSAGES / SYS_QUERY_DETAIL / SYS_QUERY_EXPLAIN / SYS_QUERY_HISTORY / SYS_QUERY_TEXT / SYS_SCHEMA_QUOTA_VIOLATIONS / SYS_SESSION_HISTORY / SYS_SPATIAL_SIMPLIFY / SYS_STREAM_SCAN_ERRORS / SYS_STREAM_SCAN_STATES / SYS_UNLOAD_DETAIL / SYS_USERLOG / SYS_VACUUM_HISTORY

個別に選択するほか、「すべてのサポート対象システムテーブル」を選ぶこともできます。すべてを選択した場合、将来追加されるビューも設定変更なしで自動的に対象に含まれます。

なお、SYS_CHILD_QUERY_TEXTSYS_COPY_REPLACEMENTSSYS_EXTERNAL_QUERY_ERRORSYS_PROCEDURE_MESSAGESSYS_QUERY_DETAILSYS_QUERY_EXPLAINSYS_SPATIAL_SIMPLIFYSYS_UNLOAD_DETAIL の 8 つはパッチ P203 以降が必要です。それより前のパッチのデータウェアハウスで有効化すると、テーブルは正しいスキーマで作成されるものの、P203 以降に更新されるまでデータが入りません。

付与されるメタデータ列

各 S3 テーブルには、元の SYS_* ビューの全列に加えて、行の出所と配信タイミングを識別するための 5 つのメタデータ列が追加されます。

列名 説明
warehouse_account_id string 元のデータウェアハウスを所有する AWS アカウント
warehouse_region_name string 元のデータウェアハウスが動作する AWS リージョン
warehouse_namespace_arn string 元のデータウェアハウスのネームスペース ARN。名前変更や再作成をまたいで不変な一意識別子
warehouse_name string 元のデータウェアハウスの名前(クラスター名またはワークグループ名)
s3_tables_ingestion_time timestamp(6), UTC Amazon Redshift が行を S3 Tables にコミットした時刻。イベント発生時刻ではなく配信時刻

2 つのデプロイモデル

配信先の構成は 2 パターンから選択します。1 つのデータウェアハウスが同時に使えるのは、いずれか一方のみです。

デプロイモデル 内容
ウェアハウス個別(per-warehouse) データウェアハウスごとに専用の S3 テーブル群へ書き込む。S3 Tables のネームスペース名にデータウェアハウス固有の識別子が含まれ、物理的に分離される
集約(consolidated) 同一アカウント・同一リージョン内の複数データウェアハウスのデータを共有の S3 テーブル群に書き込む。ネームスペース名に AWS アカウント番号が含まれ、行は warehouse_namespace_arn / warehouse_name 列で区別する

いずれも単一の AWS アカウント・単一の AWS リージョン内でのサポートです。リージョンやアカウントをまたいで分析したい場合は、クエリ実行時に各リージョン・各アカウントのテーブルの結果を結合します。クロスアカウントアクセスには AWS Glue Data Catalog の共有機能を利用できます。

対応リージョン

Amazon Redshift のプロビジョンド RA3 / RG インスタンスと Amazon Redshift Serverless で利用でき、Amazon Redshift と Amazon S3 Tables の両方がサポートされるすべての AWS 商用リージョンで提供されます。

料金への影響

システムテーブルのデータを Amazon S3 Tables へ書き込む処理自体は無料です。課金対象は以下の 2 点です。

  • 保持されるデータに対する Amazon S3 Tables の標準的なストレージ料金およびメンテナンス料金
  • データを読み取るクエリエンジンの料金(各エンジンの料金体系に従う)

利用方法

必要な権限

この機能を有効化・変更・無効化するプリンシパルには、以下の権限が必要です。

  • redshift:EnableLogging(プロビジョンドクラスター)または redshift-serverless:UpdateNamespace(Amazon Redshift Serverless)
  • s3tables:CreateTableBucket
  • s3tables:PutTableBucketEncryption
  • s3tables:PutTableBucketPolicy

有効化時、Amazon Redshift は操作を実行したプリンシパルの ID を使って S3 テーブルバケットを作成・設定します。バケット作成後のネームスペースやテーブルの作成は Amazon Redshift と Amazon S3 Tables 間のサービス信頼関係で行われるため、有効化するプリンシパルに追加の権限は不要です。

やってみた

前提条件

  • リージョン: ap-northeast-1(東京)
  • AWS CLI 2.36.27 以降
  • Amazon S3 Tables と AWS Glue Data Catalog の統合が有効(アカウント・リージョンごとに 1 回)

システム構成

20260821-amazon-redshift-0

namespace を作成する

まず配信元となる Amazon Redshift Serverless の namespace を作成します。

$ aws redshift-serverless create-namespace \
    --namespace-name systbl-s3tables \
    --db-name dev \
    --tags "key=owner,value=ishikawa-satoru" "key=purpose,value=feature-verification"
{
    "namespace": {
        "adminUsername": "admin",
        "creationDate": "2026-08-20T09:45:22.599000+00:00",
        "dbName": "dev",
        "iamRoles": [],
        "kmsKeyId": "AWS_OWNED_KMS_KEY",
        "lakehouseRegistrationStatus": "NOT_REGISTERED",
        "logExports": [],
        "namespaceArn": "arn:aws:redshift-serverless:ap-northeast-1:123456789012:namespace/2d47b4ec-cae8-4d74-bdf5-bb7f05149b3d",
        "namespaceId": "2d47b4ec-cae8-4d74-bdf5-bb7f05149b3d",
        "namespaceName": "systbl-s3tables",
        "status": "AVAILABLE"
    }
}

レスポンスに s3TablePublishStatus が含まれていません。ドキュメントの記載どおり、S3 Tables 配信を一度も設定していない namespace では返されません。

有効化する

正しいパラメータで有効化します。

% aws redshift-serverless update-namespace \
    --namespace-name systbl-s3tables \
    --log-destination-type s3table \
    --s3-table-action Enable \
    --s3-table-granularity namespace \
    --s3-table-names sys_query_history sys_connection_log
{
    "namespace": {
        "adminUsername": "admin",
        "creationDate": "2026-08-20T09:45:22.599000+00:00",
        "dbName": "dev",
        "iamRoles": [],
        "kmsKeyId": "AWS_OWNED_KMS_KEY",
        "lakehouseRegistrationStatus": "NOT_REGISTERED",
        "logExports": [],
        "namespaceArn": "arn:aws:redshift-serverless:ap-northeast-1:123456789012:namespace/2d47b4ec-cae8-4d74-bdf5-bb7f05149b3d",
        "namespaceId": "2d47b4ec-cae8-4d74-bdf5-bb7f05149b3d",
        "namespaceName": "systbl-s3tables",
        "s3TablePublishStatus": {
            "enabledAll": false,
            "s3TableGranularity": "namespace",
            "s3TableNamespace": "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys",
            "s3Tables": [
                "sys_connection_log",
                "sys_query_history"
            ]
        },
        "status": "MODIFYING"
    }
}

s3TableNamespace として 2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys が払い出されました。namespace ID のハイフンをアンダースコアに置き換え、_sys を付けた形式です。

AVAILABLE に戻ったあと、get-namespace で状態を確認します。

% aws redshift-serverless get-namespace --namespace-name systbl-s3tables
{
    "namespace": {
        "adminUsername": "admin",
        "creationDate": "2026-08-20T09:45:22.599000+00:00",
        "dbName": "dev",
        "iamRoles": [],
        "kmsKeyId": "AWS_OWNED_KMS_KEY",
        "lakehouseRegistrationStatus": "NOT_REGISTERED",
        "logExports": [],
        "namespaceArn": "arn:aws:redshift-serverless:ap-northeast-1:123456789012:namespace/2d47b4ec-cae8-4d74-bdf5-bb7f05149b3d",
        "namespaceId": "2d47b4ec-cae8-4d74-bdf5-bb7f05149b3d",
        "namespaceName": "systbl-s3tables",
        "s3TablePublishStatus": {
            "enabledAll": false,
            "lastIngestionTimes": {},
            "s3TableGranularity": "namespace",
            "s3TableNamespace": "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys",
            "s3Tables": [
                "sys_connection_log",
                "sys_query_history"
            ]
        },
        "status": "AVAILABLE"
    }
}

lastIngestionTimes が空のマップになっています。まだ 1 件も配信されていない状態です。

マネジメントコンソールで確認する

CLI で設定した内容は、マネジメントコンソールからも確認できます。Amazon Redshift Serverless のナビゲーションペインの Integrations の下に、System table integrations というメニューが追加されています。

20260821-amazon-redshift-1

一覧には、配信先の S3 テーブルバケット(aws-redshift)、データウェアハウス名(systbl-s3tables)、統合ステータス、配信対象のシステムテーブル数、テーブル統合パターンが表示されます。

namespace の詳細画面では、Integrations タブの一番下に System table integration セクションがあります。

20260821-amazon-redshift-2

--s3-table-granularity account で設定した集約モデルは、コンソール上では Shared S3 table per system table across data warehouses と表示されます。namespace 粒度の場合は Individual S3 table per system table per data warehouse です。View S3 table mapping を展開すると、各システムテーブルと S3 テーブルの対応関係を確認できます。

S3 側に何が作られたのか確認する

有効化したところで、S3 Tables 側を覗いてみます。

% aws s3tables list-table-buckets
{
    "tableBuckets": [
        {
            "arn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift",
            "name": "aws-redshift",
            "ownerAccountId": "123456789012",
            "createdAt": "2026-08-20T09:45:52.783798+00:00",
            "tableBucketId": "10a5b3d4-07b2-4faa-bdf6-8f9d6831fb05",
            "type": "aws"
        },
        {
            "arn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-s3",
            "name": "aws-s3",
            "ownerAccountId": "123456789012",
            "createdAt": "2026-06-17T01:29:37.502295+00:00",
            "tableBucketId": "4898d078-d55c-49a4-9b03-a7097812d0e0",
            "type": "aws"
        },
        {
            "arn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/variant-demo-911235df",
            "name": "variant-demo-911235df",
            "ownerAccountId": "123456789012",
            "createdAt": "2026-07-28T23:00:52.436774+00:00",
            "tableBucketId": "6b132cfc-74f5-495d-b1fd-a28037ecffb1",
            "type": "customer"
        }
    ]
}

有効化コマンドを投げた 09:45:50 のわずか 2 秒後、09:45:52 に aws-redshift バケットが自動作成されていました。typeaws になっており、自分で作った customer タイプのバケットと区別されます。

Amazon S3 コンソールの Table buckets からも同じものが見えます。

20260821-amazon-redshift-3

Type 列が AWS になっているのがサービス管理型のバケットです。作成日時も 18:45:52(JST)と、有効化した瞬間であることが確認できます。

ネームスペースを確認します。

% aws s3tables list-namespaces \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift
{
    "namespaces": [
        {
            "namespace": [
                "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys"
            ],
            "createdAt": "2026-08-20T09:45:53.179659+00:00",
            "createdBy": "123456789012",
            "ownerAccountId": "123456789012",
            "namespaceId": "ee9d3b1a-3902-48b5-86d1-8111ef3498ec",
            "tableBucketId": "10a5b3d4-07b2-4faa-bdf6-8f9d6831fb05"
        }
    ]
}

テーブルも作られています。

% aws s3tables list-tables \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift
{
    "tables": [
        {
            "namespace": [
                "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys"
            ],
            "name": "sys_connection_log",
            "type": "aws",
            "tableARN": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/cd5ec41a-ee1b-4191-9f66-54e689aa7b05",
            "createdAt": "2026-08-20T09:45:54.470424+00:00",
            "modifiedAt": "2026-08-20T09:45:54.675308+00:00",
            "managedByService": "redshift.amazonaws.com"
        },
        {
            "namespace": [
                "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys"
            ],
            "name": "sys_query_history",
            "type": "aws",
            "tableARN": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/a1c12246-54f9-4864-903d-faa9e5f4b9b6",
            "createdAt": "2026-08-20T09:45:53.693431+00:00",
            "modifiedAt": "2026-08-20T09:45:54.094134+00:00",
            "managedByService": "redshift.amazonaws.com"
        }
    ]
}

managedByServiceredshift.amazonaws.com になっており、サービスが管理するテーブルであることが分かります。個別のテーブル情報も見てみます。

% aws s3tables get-table \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift \
    --namespace 2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys \
    --name sys_query_history
{
    "name": "sys_query_history",
    "type": "aws",
    "tableARN": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/a1c12246-54f9-4864-903d-faa9e5f4b9b6",
    "namespace": [
        "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys"
    ],
    "namespaceId": "ee9d3b1a-3902-48b5-86d1-8111ef3498ec",
    "versionToken": "479231881b03bc883f64",
    "metadataLocation": "s3://a1c12246-54f9-4864-49ajcub6nguupkns5wc7fj4xckn4wapn1b--table-s3/metadata/00000-cbe5ea3d-cc05-43b1-9a45-2dabe8b108c0.metadata.json",
    "warehouseLocation": "s3://a1c12246-54f9-4864-49ajcub6nguupkns5wc7fj4xckn4wapn1b--table-s3",
    "createdAt": "2026-08-20T09:45:53.693431+00:00",
    "createdBy": "123456789012",
    "managedByService": "redshift.amazonaws.com",
    "modifiedAt": "2026-08-20T09:45:54.094134+00:00",
    "ownerAccountId": "123456789012",
    "format": "ICEBERG",
    "tableBucketId": "10a5b3d4-07b2-4faa-bdf6-8f9d6831fb05"
}

暗号化設定はデフォルトの SSE-S3 でした。

aws s3tables get-table-bucket-encryption \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift
{
    "encryptionConfiguration": {
        "sseAlgorithm": "AES256"
    }
}

バケットポリシーも自動で付与されています。

aws s3tables get-table-bucket-policy \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift
{
    "resourcePolicy": "{\"Version\":\"2012-10-17\",\"Id\":\"AWS System Tables Policy\",\"Statement\":[{\"Sid\":\"Default AWS System Tables Statement\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"systemtables.redshift.amazonaws.com\"},\"Action\":\"s3tables:*\",\"Resource\":\"*\",\"Condition\":{\"StringEquals\":{\"aws:SourceAccount\":\"123456789012\"}}}]}"
}

読みやすく整形すると、配信を行うサービスプリンシパルが明示されているのが分かります。

{
  "Version": "2012-10-17",
  "Id": "AWS System Tables Policy",
  "Statement": [
    {
      "Sid": "Default AWS System Tables Statement",
      "Effect": "Allow",
      "Principal": { "Service": "systemtables.redshift.amazonaws.com" },
      "Action": "s3tables:*",
      "Resource": "*",
      "Condition": { "StringEquals": { "aws:SourceAccount": "123456789012" } }
    }
  ]
}

メンテナンス設定も自動で構成されていました。まずはテーブル単位です。

% aws s3tables get-table-maintenance-configuration \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift \
    --namespace 123456789012_sys \
    --name sys_query_history
{
    "tableARN": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/c27c7524-ab3e-4237-b11f-e85fbf652666",
    "configuration": {
        "icebergCompaction": {
            "status": "enabled",
            "settings": {
                "icebergCompaction": {
                    "targetFileSizeMB": 512,
                    "strategy": "auto"
                }
            }
        },
        "icebergSnapshotManagement": {
            "status": "enabled",
            "settings": {
                "icebergSnapshotManagement": {
                    "minSnapshotsToKeep": 1,
                    "maxSnapshotAgeHours": 120
                }
            }
        }
    }
}

バケット単位の設定も確認します。

% aws s3tables get-table-bucket-maintenance-configuration \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift
{
    "tableBucketARN": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift",
    "configuration": {
        "icebergUnreferencedFileRemoval": {
            "status": "enabled",
            "settings": {
                "icebergUnreferencedFileRemoval": {
                    "unreferencedDays": 3,
                    "nonCurrentDays": 10
                }
            }
        }
    }
}

なお CloudTrail を見ると、テーブル作成時に PutTableRecordExpirationConfiguration が呼ばれています。

% aws cloudtrail lookup-events \
    --start-time 2026-08-20T09:45:00Z --end-time 2026-08-20T09:55:00Z \
    --lookup-attributes AttributeKey=EventName,AttributeValue=PutTableRecordExpirationConfiguration \
    --max-items 5

イベント本体から要点を抜き出すと、以下の 4 回が記録されていました。

2026-08-20T09:51:30Z PutTableRecordExpirationConfiguration redshift-serverless.amazonaws.com
  requestParameters: {"tableArn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/39551070-3476-4a0c-9239-29e0dfa626a9"}

2026-08-20T09:50:13Z PutTableRecordExpirationConfiguration redshift-serverless.amazonaws.com
  requestParameters: {"tableArn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/c27c7524-ab3e-4237-b11f-e85fbf652666"}

2026-08-20T09:45:54Z PutTableRecordExpirationConfiguration redshift-serverless.amazonaws.com
  requestParameters: {"tableArn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/a1c12246-54f9-4864-903d-faa9e5f4b9b6"}

2026-08-20T09:45:54Z PutTableRecordExpirationConfiguration redshift-serverless.amazonaws.com
  requestParameters: {"tableArn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/cd5ec41a-ee1b-4191-9f66-54e689aa7b05"}

では実際にどう設定されたのかを確認します。

% aws s3tables get-table-record-expiration-configuration \
    --table-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/c27c7524-ab3e-4237-b11f-e85fbf652666
{
    "configuration": {
        "status": "disabled"
    }
}

disabled でした。ドキュメントの「有効期限ポリシーを設定しなければデータは無期限に保持される」という記載と整合します。

テーブルスキーマを確認する

配信先テーブルのスキーマを AWS Glue Data Catalog 経由で確認します。

$ aws glue get-table \
    --catalog-id "123456789012:s3tablescatalog/aws-redshift" \
    --database-name 123456789012_sys \
    --name sys_query_history \
    --query 'Table.StorageDescriptor.Columns[*].[Name,Type]' --output text
warehouse_account_id	string
warehouse_region_name	string
warehouse_name	string
warehouse_namespace_arn	string
s3_tables_ingestion_time	timestamp
user_id	int
query_id	bigint
query_label	string
transaction_id	bigint
session_id	int
database_name	string
query_type	string
status	string
result_cache_hit	boolean
start_time	timestamp
end_time	timestamp
elapsed_time	bigint
queue_time	bigint
execution_time	bigint
error_message	string
returned_rows	bigint
returned_bytes	bigint
query_text	string
redshift_version	string
usage_limit	string
compute_type	string
compile_time	bigint
planning_time	bigint
lock_wait_time	bigint
service_class_id	int
service_class_name	string
query_priority	string
short_query_accelerated	string
user_query_hash	string
generic_query_hash	string
query_hash_version	int
result_cache_query_id	bigint
username	string
result_offloaded	string

ドキュメントに記載されている 5 つのメタデータ列が、元のビューの列より前、テーブルの先頭 5 列として付与されていました。sys_query_history の場合、元の 34 列とあわせて計 39 列になります。

Iceberg テーブルとしてのパラメータも確認しておきます。

% aws glue get-table \
    --catalog-id "123456789012:s3tablescatalog/aws-redshift" \
    --database-name 123456789012_sys \
    --name sys_query_history \
    --query '{TableType:Table.TableType, Parameters:Table.Parameters}'
{
    "TableType": "aws",
    "Parameters": {
        "createdBy": "123456789012",
        "s3TableArn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/a1c12246-54f9-4864-903d-faa9e5f4b9b6",
        "ownerAccountId": "123456789012",
        "metadata_location": "s3://a1c12246-54f9-4864-49ajcub6nguupkns5wc7fj4xckn4wapn1b--table-s3/metadata/00000-cbe5ea3d-cc05-43b1-9a45-2dabe8b108c0.metadata.json",
        "format": "ICEBERG",
        "warehouse_location": "s3://a1c12246-54f9-4864-49ajcub6nguupkns5wc7fj4xckn4wapn1b--table-s3",
        "client.region": "ap-northeast-1",
        "table_type": "ICEBERG"
    }
}

workgroup を作成してクエリを流す

配信対象のデータを作るため、workgroup を作成します。RPU は最小の 4 を指定しました。

% aws redshift-serverless create-workgroup \
    --workgroup-name systbl-s3tables-wg \
    --namespace-name systbl-s3tables \
    --base-capacity 4 \
    --publicly-accessible \
    --subnet-ids subnet-0083eff0ecf08aa2d subnet-0589d0a9773e65a8e subnet-0b78797af9323381f \
    --security-group-ids sg-0548ccd1499215c3e \
    --tags "key=owner,value=ishikawa-satoru" "key=purpose,value=feature-verification"
{
    "workgroup": {
        "workgroupName": "systbl-s3tables-wg",
        "workgroupArn": "arn:aws:redshift-serverless:ap-northeast-1:123456789012:workgroup/ae2746e7-763d-4bdd-86f5-6474082e4855",
        "workgroupId": "ae2746e7-763d-4bdd-86f5-6474082e4855",
        "namespaceName": "systbl-s3tables",
        "baseCapacity": 4,
        "maxCapacity": null,
        "status": "CREATING",
        "subnetIds": [
            "subnet-0b78797af9323381f",
            "subnet-0589d0a9773e65a8e",
            "subnet-0083eff0ecf08aa2d"
        ],
        "securityGroupIds": [
            "sg-0548ccd1499215c3e"
        ],
        "publiclyAccessible": true,
        "creationDate": "2026-08-20T09:46:45.848000+00:00",
        "port": null,
        "pricePerformanceTarget": {
            "status": "DISABLED"
        }
    }
}

base-capacity の最小値は 4 RPU です。ドキュメントによると 4 RPU、または 8 以上は 8 の倍数(8, 16, 24 ... 512)で指定できます。

https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html

約 2 分半で AVAILABLE になりました。

% aws redshift-serverless get-workgroup --workgroup-name systbl-s3tables-wg \
    --query 'workgroup.{workgroupName:workgroupName,status:status,baseCapacity:baseCapacity,endpoint:endpoint.address}'
{
    "workgroupName": "systbl-s3tables-wg",
    "status": "AVAILABLE",
    "baseCapacity": 4,
    "endpoint": "systbl-s3tables-wg.123456789012.ap-northeast-1.redshift-serverless.amazonaws.com"
}

Amazon Redshift Data API から、あとで識別できるようコメント付きのクエリを流します。

% aws redshift-data execute-statement \
    --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_01 */ SELECT 1 AS probe_one"
{
    "Id": "284c5156-8b9b-4979-88d5-95c279151517",
    "CreatedAt": "2026-08-20T20:50:41.949000+09:00",
    "DbUser": "IAMR:cm-user",
    "Database": "dev",
    "WorkgroupName": "systbl-s3tables-wg"
}
% aws redshift-data describe-statement --id 284c5156-8b9b-4979-88d5-95c279151517
{
    "Id": "284c5156-8b9b-4979-88d5-95c279151517",
    "DbUser": "IAMR:cm-user",
    "Database": "dev",
    "Duration": 27183305,
    "Status": "FINISHED",
    "CreatedAt": "2026-08-20T20:50:41.949000+09:00",
    "UpdatedAt": "2026-08-20T20:50:42.648000+09:00",
    "RedshiftPid": 1073905765,
    "HasResultSet": true,
    "QueryString": "/* s3tables_doc_20260820 */ SELECT 1 AS probe_one",
    "ResultRows": 1,
    "ResultSize": 11,
    "RedshiftQueryId": 0,
    "WorkgroupName": "systbl-s3tables-wg",
    "ResultFormat": "json"
}

同じ要領で、連番のコメントを付けたクエリを合計 8 本実行しました。実行した SQL は以下のとおりです。

aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_01 */ SELECT 1 AS probe_one"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_02 */ SELECT current_user, current_database(), version()"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_03 */ SELECT count(*) AS n FROM pg_catalog.pg_class"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_04 */ SELECT generate_series AS n FROM generate_series(1,100)"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_05 */ SELECT count(*) FROM sys_query_history"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_06 */ SELECT count(*) FROM pg_catalog.pg_tables"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_07 */ SELECT count(*) FROM pg_catalog.pg_tables"
aws redshift-data execute-statement --workgroup-name systbl-s3tables-wg --database dev \
    --sql "/* s3tables_probe_20260820_08 */ SELECT count(*) FROM pg_catalog.pg_tables"

いずれも describe-statementStatusFINISHED でした。

配信状況を確認する

配信状況は get-namespace で確認できます。

% aws redshift-serverless get-namespace --namespace-name systbl-s3tables \
    --query 'namespace.s3TablePublishStatus'
{
    "enabledAll": false,
    "lastIngestionTimes": {
        "sys_query_history": "2026-08-20T09:55:31Z",
        "sys_userlog": "2026-08-20T09:55:33Z"
    },
    "s3TableGranularity": "account",
    "s3TableNamespace": "123456789012_sys",
    "s3Tables": [
        "sys_connection_log",
        "sys_query_history",
        "sys_userlog"
    ]
}

ここで 1 点、確認時の注意があります。lastIngestionTimes が空マップのとき、--query でその値だけを取り出すと出力が空文字列になります。

% aws redshift-serverless get-namespace --namespace-name systbl-s3tables \
    --query 'namespace.s3TablePublishStatus.lastIngestionTimes' --output json
echo "(exit=$?)"
(exit=0)

配信間隔を実測する

ドキュメントには「一定の頻度でバッチ配信される」とだけ書かれており、具体的な間隔は記載がありません。そこで lastIngestionTimes をポーリングし、実際の周期を計測しました。検知した 3 回のバッチは以下のとおりです。

1 回目: 2026-08-20T09:55:31Z
2 回目: 2026-08-20T10:35:30Z (前回から 39 分 59 秒)
3 回目: 2026-08-20T11:15:24Z (前回から 39 分 54 秒)
4 回目: 2026-08-20T11:55:28Z (前回から 40 分 04 秒)

Athena から s3_tables_ingestion_time でグルーピングすると、バッチの境界がより正確に見えます。

20260821-amazon-redshift-6

配信時刻の間隔は 39 分 58.7 秒、39 分 57.0 秒、40 分 1.7 秒でした。この検証環境では約 40 分周期で配信されています。

観測された配信遅延は最短 217 秒(3 分 37 秒)、最長 2259 秒(37 分 39 秒)でした。バッチの直前に実行されたクエリは短時間で届き、バッチ直後に実行されたクエリは次のバッチまで約 40 分待つことになります。当然ながら、リアルタイム監視の用途には向きません。

CloudTrail にも配信の痕跡が残っていました。

% aws cloudtrail lookup-events \
    --start-time 2026-08-20T09:40:00Z --end-time 2026-08-20T10:35:00Z \
    --lookup-attributes AttributeKey=EventSource,AttributeValue=s3tables.amazonaws.com \
    --max-items 60
2026-08-20T09:50:12Z CreateNamespace                        | redshift-serverless.amazonaws.com
2026-08-20T09:50:12Z CreateTable                            | redshift-serverless.amazonaws.com
2026-08-20T09:50:12Z CreateTableBucket                      | redshift-serverless.amazonaws.com
2026-08-20T09:50:12Z GetTableMetadataLocation               | redshift-serverless.amazonaws.com
2026-08-20T09:50:12Z PutTableBucketPolicy                   | redshift-serverless.amazonaws.com
2026-08-20T09:50:13Z GetTableRecordExpirationConfiguration  | redshift-serverless.amazonaws.com
2026-08-20T09:50:13Z PutTableRecordExpirationConfiguration  | redshift-serverless.amazonaws.com
2026-08-20T09:50:13Z UpdateTableMetadataLocation            | redshift-serverless.amazonaws.com
2026-08-20T09:55:24Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:26Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:30Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:30Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:30Z UpdateTableMetadataLocation            | systemtables.redshift.amazonaws.com
2026-08-20T09:55:31Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:32Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:33Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:33Z GetTableMetadataLocation               | systemtables.redshift.amazonaws.com
2026-08-20T09:55:33Z UpdateTableMetadataLocation            | systemtables.redshift.amazonaws.com

イベントを時刻順に整形すると、配信時刻ちょうどに systemtables.redshift.amazonaws.com が Iceberg のメタデータをコミットしているのが分かります。配信が来ているか切り分けたいときは、CloudTrail でこのサービスプリンシパルを追うのが確実です。

Athena からクエリする(Lake Formation の壁)

この検証で使った IAM ロールはアカウント内でそれなりに強い権限を持っていますが、読み取りアクセスの管理は利用者側の責任であり、Amazon Redshift は読み取り権限を代行して適用しません。AWS Lake Formation で SELECT 権限を付与します。

% aws lakeformation grant-permissions \
    --principal DataLakePrincipalIdentifier=arn:aws:iam::123456789012:role/cm-user \
    --resource '{"Table":{"CatalogId":"123456789012:s3tablescatalog/aws-redshift","DatabaseName":"123456789012_sys","Name":"sys_query_history"}}' \
    --permissions SELECT DESCRIBE

改めてクエリすると、今度は読めました。

Athena のクエリエディタからも同様に確認できます。カタログに s3tablescatalog/aws-redshift を選ぶと、配信対象のテーブルが一覧に現れます。

20260821-amazon-redshift-4

sys_userlog も同じように読めます。こちらは 3 行でした。

20260821-amazon-redshift-5

この 2 枚はいずれも Lake Formation の SELECT 権限を付与したあとの状態です。付与前は、同じ画面から同じクエリを実行しても Relation contains no accessible columns で失敗します。

メタデータ列に注目すると、warehouse_namesystbl-s3tables、つまり namespace の名前が入っています。今回の workgroup 名は systbl-s3tables-wg なので、ドキュメントの「クラスター名またはワークグループ名」という記載とは異なり、Amazon Redshift Serverless では namespace 名が記録されるようです。

デプロイモデルを切り替えるとどうなるか

--s3-table-granularitynamespace から account に切り替えてみます。

% aws redshift-serverless update-namespace \
    --namespace-name systbl-s3tables \
    --log-destination-type s3table \
    --s3-table-action Enable \
    --s3-table-granularity account \
    --s3-table-names sys_query_history
{
    "enabledAll": false,
    "lastIngestionTimes": {},
    "s3TableGranularity": "account",
    "s3TableNamespace": "123456789012_sys",
    "s3Tables": [
        "sys_connection_log",
        "sys_query_history"
    ]
}

切り替え後、S3 テーブルバケットには新しいネームスペースが追加されました。

% aws s3tables list-namespaces \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift
{
    "namespaces": [
        {
            "namespace": [
                "2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys"
            ],
            "createdAt": "2026-08-20T09:45:53.179659+00:00",
            "createdBy": "123456789012",
            "ownerAccountId": "123456789012",
            "namespaceId": "ee9d3b1a-3902-48b5-86d1-8111ef3498ec",
            "tableBucketId": "10a5b3d4-07b2-4faa-bdf6-8f9d6831fb05"
        },
        {
            "namespace": [
                "123456789012_sys"
            ],
            "createdAt": "2026-08-20T09:50:12.270424+00:00",
            "createdBy": "123456789012",
            "ownerAccountId": "123456789012",
            "namespaceId": "af94ccca-e6db-4f7e-8f38-f2cdd0d99416",
            "tableBucketId": "10a5b3d4-07b2-4faa-bdf6-8f9d6831fb05"
        }
    ]
}

集約モデルではネームスペース名が AWS アカウント番号ベース(123456789012_sys)になります。切り替え前のネームスペースとテーブルはそのまま残りました。

% aws s3tables list-tables \
    --table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift \
    --query 'tables[].[namespace[0],name,createdAt]' --output text
2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys	sys_connection_log	2026-08-20T09:45:54.470424+00:00
2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys	sys_query_history	2026-08-20T09:45:53.693431+00:00
123456789012_sys	sys_query_history	2026-08-20T09:50:12.866435+00:00

そして、切り替え前のテーブルの行数を数えてみると、0件になりました。

SELECT count(*) AS cnt
FROM "s3tablescatalog/aws-redshift"."2d47b4ec_cae8_4d74_bdf5_bb7f05149b3d_sys"."sys_query_history";

0 行のままでした。 有効化から切り替えまでの約 4 分半に実行したクエリも、すべて切り替え後の集約テーブルに配信されています。「バックフィルしない」というドキュメントの記載が、実データで確認できました。切り替えを検討する場合は、旧テーブルと新テーブルの両方をクエリ時に結合する前提で設計する必要があります。

もう 1 点、--s3-table-names の挙動も確認しておきます。sys_userlog だけを指定して Enable してみます。

% aws redshift-serverless update-namespace \
    --namespace-name systbl-s3tables \
    --log-destination-type s3table \
    --s3-table-action Enable \
    --s3-table-granularity account \
    --s3-table-names sys_userlog \
    --query 'namespace.s3TablePublishStatus'
{
    "enabledAll": false,
    "s3TableGranularity": "account",
    "s3TableNamespace": "123456789012_sys",
    "s3Tables": [
        "sys_connection_log",
        "sys_query_history",
        "sys_userlog"
    ]

指定したテーブルで置き換えられるのではなく、既存の選択に追加されました。対象から外したい場合は --s3-table-action Disable を使う必要があります。

保持期間を設定する

保持期間は Amazon Redshift 側ではなく、Amazon S3 Tables のレコード有効期限で設定します。テーブル単位の指定です。

まず、パラメータの形を --generate-cli-skeleton で確認します。

% aws s3tables put-table-record-expiration-configuration --generate-cli-skeleton
{
    "tableArn": "",
    "value": {
        "status": "enabled",
        "settings": {
            "days": 0
        }
    }
}

この形にあわせて 30 日を設定します。

% aws s3tables put-table-record-expiration-configuration \
    --table-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/c27c7524-ab3e-4237-b11f-e85fbf652666 \
    --value '{"status":"enabled","settings":{"days":30}}'
% aws s3tables get-table-record-expiration-configuration \
    --table-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/aws-redshift/table/c27c7524-ab3e-4237-b11f-e85fbf652666
{
    "configuration": {
        "status": "enabled",
        "settings": {
            "days": 30
        }
    }
}

--table-bucket-arn--namespace / --name の組み合わせではなく、--table-arn でテーブルを直接指定する点に注意が必要です。テーブル ARN は aws s3tables list-tablestableARN、または Glue のテーブルパラメータ s3TableArn から取得できます。

補足: 連携するシステムテーブルの設定

連携するシステムテーブルの追加・削除などの管理は、マネジメントコンソールからの方が簡単に進められそうです。

20260821-amazon-redshift-7

考察

実際に触ってみて分かったことを整理します。

配信は約 40 分周期のバッチだった

公式ドキュメントは「一定の頻度」としか書いておらず、間隔は非公開です。今回の環境では 4 バッチ連続で約 40 分周期(39 分 57 秒〜40 分 2 秒)でした。あくまで 1 環境での実測値であり、保証された値ではありませんが、桁感としては「数分」ではなく「数十分」と考えておくべきです。有効化直後に配信が来ないからといって設定を疑う必要はなく、最低でも 1 時間は様子を見るのが妥当でしょう。

最大の落とし穴は Lake Formation の権限

配信自体は正常に動いていても、Lake Formation の SELECT 権限がなければ列は 1 つも読めません。しかも count(*) は通るため、「行数は見えるのにデータが読めない」という分かりにくい状態になります。導入時は、配信の確認とアクセス権の付与を別々のタスクとして計画しておくべきです。裏を返せば、機微な情報を含むシステムテーブルに対して、デフォルトで誰にも読めない状態から始められるということでもあり、ガバナンス上は望ましい設計といえます。

サービス管理型リソースの範囲が広い

S3 テーブルバケット、ネームスペース、テーブル、バケットポリシー、暗号化設定、コンパクションとスナップショットのメンテナンス設定まで、すべて自動で構成されました。有効化コマンド 1 本から 2 秒でバケットが生成される速さは印象的です。一方で、これらは利用者側で作った覚えのないリソースとして増えるため、S3 テーブルバケットの棚卸しルールがある組織では事前に周知しておいたほうがよさそうです。typeaws になるので、customer タイプのバケットとは区別できます。

デプロイモデルの切り替えはバックフィルされない

namespace から account への切り替えで、切り替え前のテーブルは 0 行のまま取り残されました。バックフィルされないという仕様は把握していても、実際に 0 行を見ると影響の大きさが実感できます。デプロイモデルは最初に決め切るべきです。

確認スクリプトはエラーを握り潰さない作りにする

--query で目的の値だけを取り出す書き方は簡潔ですが、API エラー時も空文字列が返るため、認証切れと「まだ配信されていない」を区別できません。検証中に実際にこれで誤診しました。監視を自動化する場合は生の JSON を取得し、エラーを明示的に判定する実装にしてください。

費用は極めて小さい

今回の検証で消費した Amazon Redshift Serverless のコンピューティングは、CloudWatch の ComputeSeconds で合計 137 RPU 秒でした。東京リージョンの $0.494 / RPU-Hr で換算すると約 $0.02 です。namespace と workgroup はアイドル状態では課金されないため、待ち時間が長くてもコストは膨らみません。一方、データは固定の頻度でバッチ配信されるため、リアルタイム性が求められる用途には向きません。

最後に

Amazon Redshift のシステムテーブルを、クラスター内 7 日間の保持期間を超えて Amazon S3 Tables に長期保持できるようになりました。テーブル作成からスキーマ進化、コンパクション、スナップショット管理まで AWS 側が管理するため、これまで長期保持のために組んでいた独自 ETL パイプラインを廃止できる可能性があります。

実際に試してみると、有効化自体は CLI 1 コマンドで完了し、S3 側のリソースも 2 秒で自動生成されました。一方で、配信が約 40 分周期のバッチであること、Lake Formation の権限がないと列を読めないことなど、事前に把握しておかないと戸惑うポイントもあります。

まずは sys_query_history など必要なシステムテーブルだけを対象に、namespace 粒度の小さな構成で有効化し、データ量と保持期間の設計を進めてみてはいかがでしょうか。

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事