これは PostgreSQL Advent Calendar 2020 25 日目のエントリです。
昨日は Yugo Nagata (yugo-n) さんでした。
AWS のサービスをあまり追いかけていない間(10 月頃?)に RDS の Graviton2 プロセッサ対応が GA になっていました。
MySQL Advent Calendar 2020 のほうでは EC2 の Graviton2 インスタンスに MySQL を入れて試しましたが(「MySQL 8.0.22 で innodb_log_writer_threads の効果を見てみる」)、こちらでは RDS の PostgreSQL 12.4R1 で試してみます。
テスト内容
**第 19 回 PostgreSQL アンカンファレンス @ オンライン**のネタで(db.m5.xlarge インスタンスに対して)試した内容を db.m6g.xlarge インスタンスを使って再現し、db.m5.xlarge インスタンスの結果と比較しました。
-
MySQL と PostgreSQL と主キー
- 中小規模の MySQL と PostgreSQL では、主キーにシーケンス値(
AUTO_INCREMENT
/serial
)を使うべきか UUIDv4 を使うべきか(実験してみた)、という話。
- 中小規模の MySQL と PostgreSQL では、主キーにシーケンス値(
先に記しておくと、中小規模・書き込みノード 1 つの PostgreSQL では、UUIDv4 よりもシーケンス値(serial
)を使ったほうが高速で、かつ安定していました。
今回は db.m6g.xlarge(Graviton2)と db.m5.xlarge(Intel x86_64)の間で性能差と特性の違いの有無を見てみました。
テスト環境
- Amazon(AWS) RDS(PostgreSQL 12.4 R1)
- db.m6g.xlarge / db.m5.xlarge インスタンス(いずれも 4vCPU / メモリ 16GiB)を比較
- ストレージは SSD 700GiB
- Single AZ
- デフォルトパラメータグループ
テスト内容詳細
中小規模のシステム想定でひたすら行挿入をしたときの、主キーの種類別パフォーマンスを比較するものです。
今回は主キーの種類別に、Graviton2 と Intel x86_64 の速度を比較しつつ、それぞれの特性に違いがないか確認しました(MySQL との比較は外しました)。
- 120 万行のデータを 24 並列で挿入(合計 2,880 万行)
- 主キーとして以下の 3 種類を使い、挿入 100 万行あたりの所要時間の推移を確認
- (ⅰ)
serial
- (ⅱ) UUIDv4(文字列)
- (ⅲ) UUIDv4(
uuid
型)
- (ⅰ)
- テストに使うテーブルとして、以下の 2 種類を用意
- (1) 主キー列 +
integer
列 +timestamp
列 - (2) 主キー列 +
integer
列 +varchar(100)
列(デフォルトで 100 文字入れる) +timestamp
列
- (1) 主キー列 +
テストに使用したテーブル
- (1) 主キー列 +
integer
列 +timestamp
列
-- (ⅰ) serial
CREATE TABLE btree_test2 (id serial PRIMARY KEY NOT NULL, v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp);
-- (ⅱ) uuid_txt
CREATE TABLE btree_test3 (id char(36) PRIMARY KEY NOT NULL, v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp);
-- (ⅲ) uuid
CREATE TABLE btree_test4 (id uuid PRIMARY KEY NOT NULL, v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp);
- (2) 主キー列 +
integer
列 +varchar(100)
列 +timestamp
列
-- (ⅰ) serial
CREATE TABLE btree_test2 (id serial PRIMARY KEY NOT NULL, v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp, s1 varchar(100) DEFAULT '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
-- (ⅱ) uuid_txt
CREATE TABLE btree_test3 (id char(36) PRIMARY KEY NOT NULL, v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp, s1 varchar(100) DEFAULT '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
-- (ⅲ) uuid
CREATE TABLE btree_test4 (id uuid PRIMARY KEY NOT NULL, v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp, s1 varchar(100) DEFAULT '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
テストに使用した SQL(文)の一部
-- (ⅰ) serial
INSERT INTO btree_test2 (v1) VALUES (10), (11), (12), (13), (14), (15), (16), (17), (18), (19);
-- これを 12 万行 1 ファイル × 24 種類用意
-- (ⅱ) uuid_txt
INSERT INTO btree_test3 (id, v1) VALUES ('23ce3e9f-16de-4e5c-a293-6104ca45b47a', 10), ('ccf75ce2-49e9-4585-8561-9c55acf9e954', 11), ('493ec339-a21c-4ae9-be52-8c313758dd77', 12), ('aee11198-7767-42a6-9363-a16556d936b7', 13), ('7133eb96-fe19-4d45-b2f7-62ddc719234d', 14), ('cc1ae2ee-d99e-4102-9288-877eaae3bddc', 15), ('67fc7a86-b3c8-46fa-a237-d6479ee693b5', 16), ('c2e663e1-0168-4084-97fb-97b7d4575cf6', 17), ('602f2007-76f4-45d7-8a0f-e51430943afe', 18), ('f2b1ce06-db4a-48c4-b089-94198d3ddbe9', 19);
-- これを(異なる UUID で)12 万行 1 ファイル × 24 種類用意
-- (ⅲ) uuid
INSERT INTO btree_test4 (id, v1) VALUES ('23ce3e9f-16de-4e5c-a293-6104ca45b47a'::uuid, 10), ('ccf75ce2-49e9-4585-8561-9c55acf9e954'::uuid, 11), ('493ec339-a21c-4ae9-be52-8c313758dd77'::uuid, 12), ('aee11198-7767-42a6-9363-a16556d936b7'::uuid, 13), ('7133eb96-fe19-4d45-b2f7-62ddc719234d'::uuid, 14), ('cc1ae2ee-d99e-4102-9288-877eaae3bddc'::uuid, 15), ('67fc7a86-b3c8-46fa-a237-d6479ee693b5'::uuid, 16), ('c2e663e1-0168-4084-97fb-97b7d4575cf6'::uuid, 17), ('602f2007-76f4-45d7-8a0f-e51430943afe'::uuid, 18), ('f2b1ce06-db4a-48c4-b089-94198d3ddbe9'::uuid, 19);
-- 同上
テスト結果
(1) 主キー列 + integer
列 + timestamp
列
まずは「サイズの小さい行をひたすら挿入」のパターンです。
(I) が Intel x86_64、(G) が Graviton2 です。挿入 100 万行ごとに所要時間をプロットしています。縦軸は秒数です。
前述のとおり、主キーがserial
のときに一番速く、かつ安定しています。
Intel x86_64 と Graviton2 の比較では、主キーがserial
の場合は Intel x86_64 のほうが速くなりました。
逆に、主キーがchar(36)
の UUIDv4 では、わずかに Graviton2 のほうが速くなりました。
(2) 主キー列 + integer
列 + varchar(100)
列 + timestamp
列
(1) よりも 1 行のサイズが大きいパターンです。
(1) と同じで主キーがserial
のときに一番速く、かつ安定しています。
なお、こちらは Intel x86_64・Graviton2 の間での差がほとんどなくなりました。
例外として、主キーがchar(36)
の UUIDv4 のみ Graviton2 のほうが速くなりました。
【参考】テスト実行時のパフォーマンスインサイト
【おまけ 1 】(1) の (ⅲ) で、主キーの生成にuuid-ossp
のuuid_generate_v4()
を使用すると…
「Graviton2 など Arm プロセッサでは乱数のエントロピー不足による性能問題が発生しやすい」という話がありましたので、念のためuuid-ossp
を使って UUIDv4 を PostgreSQL 側で生成するパターンも試してみました。
- 【参考】Amazon EC2 を Arm に切り替えたら幸せなことしかありませんでした(CyberAgent Developers Blog)
CREATE EXTENSION "uuid-ossp";
CREATE TABLE btree_test2 (id uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), v1 integer, t1 timestamp(6) NOT NULL DEFAULT current_timestamp);
※SQL(文)は (ⅰ) serial と同じものを使用。
UUIDv4 の生成にわずかに時間が掛かるものの、明確な処理の滞留は見られませんでした。
※主キーがuuid
型の場合、挿入行数が増えてくるとuuid-ossp
を使わなくても処理が遅くなり単位行あたりの所要時間のばらつきも大きくなりましたが、uuid-ossp
を使ってもその傾向はほぼ変わりませんでした。
【おまけ 2 】RDS でのインスタンスタイプ(インスタンスクラス)の変更
EC2 の場合とは異なり、Intel x86_64 と Graviton2 の間でも変更可能です。
まとめ
EC2 インスタンスに MySQL 8.0.22 を入れて試したときは、
- 2vCPU までなら Graviton2 が高速
- 8vCPU 以上なら概ね Intel x86_64 が高速
でしたが、今回の RDS PostgreSQL の 4vCPU 環境では**「ほぼ同等の性能」**という結果が出ました。
今回試したワークロードはある意味特殊ですのでこれだけで全てを判断することはできませんが、概ね MySQL on EC2 の結果と整合していますので、なんとなく傾向は掴める…かもしれません2020/12/26 の追記にあるpgbench
の結果をあわせて考えると、MySQL on EC2 の結果とは少し傾向が異なる模様です。
また、今後 Graviton2 への最適化が進むとさらに結果は変わるかもしれません。
※実環境で使う場合は、使い方に合わせて性能調査を行いましょう。
2020/12/26 追記:
さすがにワークロードがINSERT
に偏りすぎなので、本編とは別に、pgbench
も掛けてみました。
ただし、あえてメモリに載る容量を意図してフィルファクタは600
としています。
- テーブル初期化
pgbench -i -s 600 -U postgres -h 【RDSエンドポイント】 -d pgbench
- ベンチマーク実行
pgbench -N -r -c 【スレッド数】 -j 【スレッド数】 -T 300 -U 【RDSエンドポイント】 -d pgbench
- m6g.xlarge vs m5.xlarge
縦軸は TPS、横軸はスレッド数です。4vCPU・メモリ 16GiB の m6g.xlarge と m5.xlarge では m6g.large(Graviton2)のほうが良い結果が出ました。
- m6g.4xlarge vs m5.4xlarge
16vCPU・メモリ 64GiB の m6g.4xlarge と m5.4xlarge でも m6g.4xlarge(Graviton2)のほうが良い結果が出ましたが、40 スレッド以上では SSD の IOPS 上限(書き込み約 14,000)に当たってしまいました(プロビジョンドの SSD を使ってベンチマークを取る必要がありますね)。
より vCPU の多いインスタンスでプロビジョンドの SSD を使って確認する必要がありますが、pgbench
の結果は MySQL 8.0.22 on EC2 でmysqlslap
を実行したときとは少し傾向が違うようです(mysqlslap
のmixed
では並列スレッド数を増やしても IOPS が上限に張り付く状況にはなりませんでした)。
2020/12/26 追記その 2:
RDS MySQL を使って「追試」してみました。