ablog

不器用で落着きのない技術者のメモ

Redshift の COPY コマンドでロード時に無効な UTF-8 文字を自動的に置換する

COPY コマンドで Redshift にデータロード時に無効な UTF-8 文字がある場合、ACCEPTINVCHARS で固定の文字列に置換することができる。

ACCEPTINVCHARS [AS] ['replacement_char']
データに無効な UTF-8 文字がある場合でも、VARCHAR 列へのデータのロードを有効にします。ACCEPTINVCHARS を指定した場合、COPY は replacement_char で指定されている文字列から構成される同じ長さの文字列で、無効な各 UTF-8 文字を置き換えます。たとえば、置換文字が '^' である場合、無効な 3 バイト文字は '^^^' で置き換えられます。

置換文字には NULL 以外の任意の ASCII 文字を使用できます。デフォルトは疑問符 (?) です。無効な UTF-8 文字の詳細については、「マルチバイト文字のロードエラー」を参照してください。

COPY は無効な UTF-8 文字を含んだ行の数を返し、対象行ごとに STL_REPLACEMENTS システムテーブルにエントリを追加します (各ノードスライスで最大 100 行まで)。さらに多くの無効な UTF-8 文字も置き換えられますが、それらの置換イベントは記録されません。

ACCEPTINVCHARS を指定しなかった場合、無効な UTF-8 文字があるごとに、COPY はエラーを返します。

ACCEPTINVCHARS は VARCHAR 列に対してのみ有効です。

データ変換パラメータ - Amazon Redshift

Redshift で COPY コマンド実行時に svl_query_metrics_summary や sys_query_history に情報が記録されるか

Redshift で COPY コマンド実行時に svl_query_metrics_summary や sys_query_history に情報が記録されることを確認したメモ。

結果

dev=# copy public.customer from 's3://test-rs-copy-bucket/csv/customer/' csv
dev-# iam_role 'arn:aws:iam::123456789012:role/redshift-spectrum-s3-fullaccess';
INFO:  Load into table 'customer' completed, 9000000 record(s) loaded successfully.
COPY
Time: 8538.877 ms (00:08.539)
dev=# select pg_last_query_id();
 pg_last_query_id 
------------------
         33416134
(1 row)

Time: 3.421 ms
dev=# \gset
Time: 3.452 ms
dev=# \x
Expanded display is on.
dev=# select * from svl_query_metrics_summary where query = :pg_last_query_id;
-[ RECORD 1 ]--------------+-----------------------------------------------------------------
userid                     | 100
query                      | 33416134
service_class              | 102
query_cpu_time             | 14
query_blocks_read          | 160
query_execution_time       | 8
query_cpu_usage_percent    | 40.07
query_temp_blocks_to_disk  | 
segment_execution_time     | 3
cpu_skew                   | 1.91
io_skew                    | 1.00
scan_row_count             | 8850432
join_row_count             | 
nested_loop_join_row_count | 
return_row_count           | 
spectrum_scan_row_count    | 
spectrum_scan_size_mb      | 
query_queue_time           | 
service_class_name         | Default queue                                                   

Time: 682.883 ms
dev=# select * from sys_query_history where transaction_id = (select xid from stl_query where query = :pg_last_query_id);
-[ RECORD 1 ]----+------------------------------------------------------------------------------------------------
user_id          | 100
query_id         | 33416133
query_label      | default
transaction_id   | 93744987
session_id       | 1073889466
database_name    | dev
query_type       | COPY
status           | success   
result_cache_hit | f
start_time       | 2024-09-06 00:04:43.957806
end_time         | 2024-09-06 00:04:51.574099
elapsed_time     | 7616293
queue_time       | 0
execution_time   | 7491272
error_message    | 
returned_rows    | 0
returned_bytes   | 0
query_text       | copy public.customer from 's3://test-rs-copy-bucket/csv/customer/' csv\niam_role '';
redshift_version | 1.0.73348                       
usage_limit      | 
compute_type     | primary
compile_time     | 6539232
planning_time    | 0
lock_wait_time   | 36

Time: 790.980 ms

手順

create table public.customer 
(
  c_custkey      integer not null,
  c_name         varchar(25) not null,
  c_address      varchar(25) not null,
  c_city         varchar(10) not null,
  c_nation       varchar(15) not null,
  c_region       varchar(12) not null,
  c_phone        varchar(15) not null,
  c_mktsegment   varchar(10) not null
)
diststyle even
compound sortkey(c_nation,c_region);

copy public.customer from 's3://test-rs-copy-bucket/csv/customer/' csv
iam_role 'arn:aws:iam::123456789012:role/redshift-spectrum-s3-fullaccess';

select pg_last_query_id();
\gset

\x
select * from svl_query_metrics_summary where query = :pg_last_query_id;
select * from sys_query_history where transaction_id = (select xid from stl_query where query = :pg_last_query_id);

Redshift の STL テーブルと SYS ビュー

Redshift の STL テーブルのクエリID(query列)と SYS ビューのクエリID(query_id)は別の値のため、クエリIDで結合することはできない。トランザクションID(STLとSYSのトランザクションIDが 1:1 の場合)で結合することができる。

dev=# \timing on
dev=# select count(distinct(lo_orderkey)) from lineorder;
   count
-----------
 150000000
(1 row)

Time: 13282.862 ms (00:13.283)
dev=# select pg_last_query_id();
 pg_last_query_id
------------------
         33269125
(1 row)

Time: 3.632 ms
dev=# \gset
Time: 3.703 ms
dev=# \x
Expanded display is on.
dev=# select * from sys_query_history where transaction_id = (select xid from stl_query where query = :pg_last_query_id);
-[ RECORD 1 ]----+----------------------------------------------------
user_id          | 100
query_id         | 33269123
query_label      | default
transaction_id   | 93596628
session_id       | 1073922183
database_name    | dev
query_type       | SELECT
status           | success
result_cache_hit | f
start_time       | 2024-09-05 04:25:48.409507
end_time         | 2024-09-05 04:26:01.689166
elapsed_time     | 13279659
queue_time       | 0
execution_time   | 13263519
error_message    |
returned_rows    | 1
returned_bytes   | 15
query_text       | select count(distinct(lo_orderkey)) from lineorder;
redshift_version | 1.0.73348
usage_limit      |
compute_type     | primary
compile_time     | 155
planning_time    | 6009
lock_wait_time   | 22

Time: 378.407 ms

参考

SYS monitoring views such as such as SYS_QUERY_HISTORY and SYS_QUERY_DETAIL contain the query_id column, which holds the identifier for users’ queries. Similarly, provisioned-only views such as STL_QUERY and SVL_QLOG contain the query column, which also holds the query identifiers. However, the query identifiers recorded in the SYS system views are different from those recorded in the provisioned-only views.

The difference between the SYS views’ query_id column values and the provisioned-only views’ query column values is as follows:

In SYS views, the query_id column records user-submitted queries in their original form. The Amazon Redshift optimizer might break them down into child queries for improved performance, but a single query you run will still only have a single row in SYS_QUERY_HISTORY. If you want to see the individual child queries, you can find them in SYS_QUERY_DETAIL.

In provisioned-only views, the query column records queries at the child query level. If the Amazon Redshift optimizer rewrites your original query into multiple child queries, there will be multiple rows in STL_QUERY with differing query identifier values for a single query you run.

When you migrate your monitoring and diagnostic queries from provisioned-only views to SYS views, consider this difference and edit your queries accordingly. For more information on how Amazon Redshift processes queries, see Query planning and execution workflow.

System tables and views reference - Amazon Redshift

Redshift のシステムテーブルビューの種類

STL STV SVL SVV SYS
タイプ テーブル テーブル ビュー ビュー ビュー
生成方法 ディスク上のログ オンメモリーデータ STLへの参照 STVへの参照 -
用途 過去の実行記録の参照 現在進行中の処理の参照 STL/STVデータを組み合わせて別軸で分析 同左 -
記録タイミング 実行直後* - 実行中 - -
保持期間 7日間 - 7日間 - 7日間
  • * 検証結果より、ただし実行時間が短いと記録されないこともある

参考

STL システムビューは 7 日間のログ履歴を保持します。ログの保持は、すべてのクラスターサイズとノードタイプで保証されており、クラスターワークロードの変化による影響を受けません。また、ログの保持は、クラスターの一時停止などのクラスターの状態からも影響を受けません。クラスターが新しい場合のみ、ログ履歴が 7 日未満になります。ログを保持するために必要なアクションはありませんが、7 日以上前のログデータを保持するには、ログを定期的に他のテーブルにコピーするか、Amazon S3 にアンロードする必要があります。

ログ記録のための STL ビュー - Amazon Redshift
  • Redshift に存在するユーザー作成でないスキーマ一覧。
dev=# select nspname from pg_namespace where nspowner = 1;
      nspname
--------------------
 pg_toast
 pg_internal
 pg_automv
 pg_temp_1
 pg_catalog
 information_schema
 catalog_history
 public
 pg_temp_7
 pg_temp_8
 pg_temp_9
 pg_temp_5
 pg_temp_6
 pg_temp_11
 pg_auto_copy
 pg_s3
 pg_mv
(17 rows)
dev=# select distinct(split_part(tablename,'_',1)) from  pg_tables where schemaname = 'pg_catalog';
 split_part
------------
 padb
 pg
 stcs
 stll
 stv
 systable
(6 rows)
dev=# select distinct(split_part(viewname,'_',1)) from  pg_views where schemaname = 'pg_catalog';
 split_part
------------
 pg
 stl
 svcs
 svl
 svv
 sys
(6 rows)
  • STL/SVL には実行直後に記録されるが、実行時間が短いクエリは記録されない。
$ psql "host=redshift-cluster-poc-central.********.ap-northeast-1.redshift.amazonaws.com user=awsuser dbname=dev port=5439"
psql (13.7, server 8.0.2)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

dev=# \pset pager
Pager usage is off.
dev=# select version();
                                                          version
---------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.73348
(1 row)

dev=# set enable_result_cache_for_session=off;
SET
dev=#  \timing on
Timing is on.
dev=# select count(*) from lineorder;
   count
------------
 1200075804
(1 row)

Time: 31.825 ms
dev=# select pg_last_query_id();
 pg_last_query_id
------------------
         33268129 
(1 row)

Time: 3.663 ms ★クエリの実行時間は約3.6ミリ秒
dev=# \gset
Time: 3.583 ms
dev=# select userid,query,query_execution_time,query_blocks_read from svl_query_metrics_summary where query = :pg_last_query_id;
 userid | query | query_execution_time | query_blocks_read
--------+-------+----------------------+-------------------
(0 rows) ★記録されていない

Time: 243.333 ms
dev=# select count(distinct(lo_orderkey)) from lineorder;
   count
-----------
 150000000
(1 row)

Time: 11748.946 ms (00:11.749)
dev=# select pg_last_query_id();
 pg_last_query_id
------------------
         33268148
(1 row)

Time: 3.521 ms ★クエリの実行時間は3.5秒
dev=# \gset
Time: 3.580 ms
dev=# select userid,query,query_execution_time,query_blocks_read from svl_query_metrics_summary where query = :pg_last_query_id;
 userid |  query   | query_execution_time | query_blocks_read
--------+----------+----------------------+-------------------
    100 | 33268148 |                   12 |              4269
(1 row) ★記録されている

Time: 230.942 ms

AWS Summit Tokyo 2023 で発表した "Amazon Redshift クエリパフォーマンスチューニング Deep Dive" のスライド

今更だけど、社内外でよく2023年のAWSサミット東京で発表した "Amazon Redshift クエリパフォーマンスチューニング Deep Dive" のスライドのパスをよく聞かれるのでメモしておく。

発表後に SYS_QUERY_HISTORY など便利なビューも増えている。

Redshift に Parquet を COPY コマンドでロードしようとすると 15007 Spectrum Scan Error が発生

事象

Redshift に Parquet を COPY コマンドでロードしようとすると 15007 Spectrum Scan Error が発生する。

  • 実行コマンド
copy t2 from 's3://s3-prod-123456789012-ap-northeast-1/table-data/t1/' parquet
iam_role 'arn:aws:iam::123456789012:role/PROD_IAMRole';
  • エラーメッセージ
ERROR:  Spectrum Scan Error
DETAIL:
  -----------------------------------------------
  error:  Spectrum Scan Error
  code:      15007
  context:   Forbidden: HTTP response error code: 403 Message: AccessDenied Access Denied
x-amz-request-id: ...
x-amz-id-2: ...
  query:     612423
  location:  dory_util.cpp:1611
  process:   worker_thread [pid=22941]
  -----------------------------------------------

AWS CLI からアクセスするサービスのエンドポイントを aws/config で指定する

実行例

$ aws s3 ls --profile s3_access --debug

...

2024-08-07 05:06:29,995 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): bucket.vpce-********-********.s3.ap-northeast-1.vpce.amazonaws.com:443

AWS CLI の設定

  • ~/.aws/config
[profile s3_access]
region = ap-northeast-1
role_arn = arn:aws:iam::123456789012:role/s3-role
source_profile=s3_access
services = custom-endpoint

[services custom-endpoint]
s3 =
        endpoint_url = https://bucket.vpce-********-*********.s3.ap-northeast-1.vpce.amazonaws.com
sts =
        endpoint_url = https://vpce-********-********.sts.ap-northeast-1.vpce.amazonaws.com
  • ~/.aws/credentials
[s3_access]
aws_access_key_id = ********
aws_secret_access_key = ********

参考

エンドポイント設定は、システム環境変数やユーザー環境変数AWS ローカル設定ファイルなど、複数の場所に配置されているほか、コマンドラインでパラメータとして明示的に宣言されています。 AWS CLI エンドポイント構成設定は、次の順序で優先されます。

  1. --endpoint-url コマンドラインオプション。
  2. 有効にすると、AWS_IGNORE_CONFIGURED_ENDPOINT_URLS グローバルエンドポイント環境変数またはプロファイル設定 ignore_configure_endpoint_urls はカスタムエンドポイントを無視します。
  3. サービス固有の環境変数 AWS_ENDPOINT_URL_ (AWS_ENDPOINT_URL_DYNAMODB など) によって提供される値。
  4. AWS_USE_DUALSTACK_ENDPOINT、AWS_USE_FIPS_ENDPOINT、および AWS_ENDPOINT_URL 環境変数によって提供される値。
  5. 共有 config ファイルの services セクション内の endpoint_url 設定によって提供されるサービス固有のエンドポイント値。
  6. 共有 config ファイルの profile 内の endpoint_url 設定によって提供される値。
  7. use_dualstack_endpoint、use_fips_endpoint、および endpoint_url の設定。
  8. それぞれのデフォルトエンドポイント URL AWS のサービス は最後に使用されます。各リージョンで使用できる標準的なサービスエンドポイントについては、「Amazon Web Services 全般のリファレンス」の「AWS リージョンとエンドポイント」を参照してください。
設定ファイルと認証情報ファイルの設定 - AWS Command Line Interface