Snowflake - Hybrid Table / Unistoreのパフォーマンスを検証してみた!
この記事は何
Snowflake Summit 2022にて発表された Hybrid Tableをデモ環境にて検証することが出来たので、検証内容とその結果をまとめました。
なお、Hybrid TableについてはPrivate Previewの機能となっており、今回の検証は記事公開時点(2022年8月30日)での検証内容であることにご留意ください。
Hybrid Tableとは
Hybrid Tableは、Snowflake上で作成できるOLTP向けテーブルのことで、これまでのOLAP向けテーブルとのシームレスな統合を実現することができます。
Snowflakeが提唱するUnistoreと呼ばれるOLTP/OLAPの統合ワークロードの核となる機能として提供されています。
手前味噌にはなりますが、より詳しい内容はこちらをご確認いただければと思います。
検証環境
検証に使うデータ
今回は、以下のようなデモデータを用いて検証を行います。
各テーブルのSQL定義は以下のようになります。Hybrid Tableの場合は、Primary Keyの設定が必須です。
create or replace hybrid table region_hybrid (
r_regionkey number not null primary key,
r_name string not null,
r_comment string
);
create or replace hybrid table nation_hybrid (
n_nationkey number not null primary key,
n_name string not null,
n_regionkey number not null,
n_comment string not null,
constraint fK_regionkey foreign key (n_regionkey) references region_hybrid(r_regionkey)
);
create or replace hybrid table customer_hybrid (
c_custkey number not null primary key,
c_name string not null,
c_address string not null,
c_nationkey number not null,
c_phone string not null,
c_acctbal number not null,
c_mktsegment string,
c_comment string,
constraint fk_nationkey foreign key (c_nationkey) references nation_hybrid(n_nationkey)
);
create or replace hybrid table orders_hybrid (
o_orderkey number not null primary key,
o_custkey number not null,
o_orderstatus string not null,
o_totalprice number not null,
o_orderdate date not null,
o_orderpriority string not null,
o_clerk string not null,
o_shippriority string not null,
o_comment string not null,
constraint fk_custkey foreign key (o_custkey) references customer_hybrid(c_custkey)
);
各テーブルのレコード数は以下の通りです。
Region | Nation | Customer | Orders |
---|---|---|---|
5行 | 25行 | 15万行 | 150万行 |
今回は比較のため、同じカラム定義で通常のテーブルも用意します。
検証に使ったウェアハウス
今回は、Snowflakeでの最小のウェアハウスサイズである「XS」を利用して検証します。今回のデモ環境では、ウェアハウスのサイズを変更することができなかったため、他のサイズでのパフォーマンスについては別の機会に検証したいと思います。
検証その1: トランザクション処理
Hybrid Tableが得意とするトランザクション処理について、通常のTableと比較して、どれくらいのパフォーマンス差異があるのかを検証してみます。
一般的な以下のユースケースについて検証してみます。
- ある特定の1レコードを取得する (SELECT)
- ある特定のレコードを追加する (INSERT)
- ある特定のレコードを更新する (UPDATE)
- ある特定のレコードを削除する (DELETE)
今回は、連続して5回クエリを発行してみて、クエリパフォーマンスを調べます。
SELECT
Primary Keyをwhere句で指定した形のよくあるクエリを発行してみます。
-- 通常のTable
select * from customer
where c_custkey = 50000
;
-- Hybrid Table
select * from customer_hybrid
where c_custkey = 50000
;
結果は以下のようになりました。今回はウェアハウスを立ち上げたまま連続で5回クエリしたため、各種キャッシュが効いています。通常のTableの場合、2回目以降はQuery Result Cacheが効いているので30ms程度でレスポンスしています。一方、Hybrid Tableの場合、Query Result Cacheが効かないため、徐々に改善するものの、100ms前後に留まる形となっています。
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 338ms | 56ms | 42ms | 38ms | 34ms |
Hybrid Table | 341ms | 167ms | 139ms | 92ms | 98ms |
では、より行数の多いテーブルでどうなるかも見てみます。
-- Table
select * from orders
where o_orderkey = 5000000
;
-- Hybrid Table
select * from orders_hybrid
where o_orderkey = 5000000
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 1.6s | 68ms | 44ms | 45ms | 34ms |
Hybrid Table | 353ms | 256ms | 104ms | 96ms | 92ms |
より行数が多いと、通常のテーブルでは初回のクエリにかなり時間がかかるようになった一方、Hybrid Tableではパフォーマンスがあまり低下していません。
INSERT
次に、5回に分けて1レコードずつ追加してインサート処理のパフォーマンスを検証してみたいと思います。
-- 通常のTable
insert into customer
values (0, 'Created', 'xxxxx', 23, '00-000-000-0000', 0.0, 'created', 'created')
;
-- 以下、PKの値を変えてレコードを追加
-- Hybrid Table
insert into customer_hybrid
values (0, 'Created', 'xxxxx', 23, '00-000-000-0000', 0.0, 'created', 'created')
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 520ms | 407ms | 530ms | 466ms | 835ms |
Hybrid Table | 223ms | 167ms | 136ms | 183ms | 170ms |
インサート処理に関しては、明確にHybrid Tableの方が3倍程度早くなっています。
よりデータ量が多いテーブルではどうなるかも見てみます。
-- 通常のTable
insert into orders
values (0, 1, 'O', 100, '2022-08-01', 'xxx', 'xxx', 0, 'created')
;
-- Hybrid Table
insert into orders_hybrid
values (0, 1, 'O', 100, '2022-08-01', 'xxx', 'xxx', 0, 'created')
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 629ms | 459ms | 365ms | 482ms | 373ms |
Hybrid Table | 179ms | 399ms | 160ms | 139ms | 119ms |
どちらのケースでもパフォーマンスはあまり変わりませんでした。
UPDATE
更新処理についても、同じレコードを5回連続で更新してみて、処理速度を確かめてみます。
-- 通常のTable
update customer set c_comment = 'updated'
where c_custkey = 50000
;
-- Hybrid Table
update customer_hybrid set c_comment = 'updated'
where c_custkey = 50000
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 3.5s | 827ms | 997ms | 933ms | 902ms |
Hybrid Table | 206ms | 211ms | 193ms | 446ms | 189ms |
インサート処理に比べると、より差が明確になりました。4-5倍の速度差が生じています。
より大きいテーブルに対しても検証してみます。
-- Table
update orders set o_comment = 'updated'
where o_orderkey = 5000000
;
-- Hybrid Table
update orders_hybrid set o_comment = 'updated'
where o_orderkey = 5000000
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 3.0s | 1.5s | 1.4s | 1.4s | 1.2s |
Hybrid Table | 351ms | 332ms | 172ms | 164ms | 178ms |
通常のTableでは速度低下が見られる一方、Hybrid Tableはほとんど性能劣化していません。
レコードを削除する
最後に、レコードを1つずつ、5回削除してみます。追加処理の検証で作成したレコードを削除していきます。
-- 通常のTable
delete from customer
where c_custkey = 0
;
-- Hybrid Table
delete from customer_hybrid
where c_custkey = 0
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 1.2s | 602ms | 460ms | 473ms | 307ms |
Hybrid Table | 337ms | 194ms | 165ms | 160ms | 167ms |
更新処理ほどではありませんでしたが、こちらも、Hybrid Tableの方が早い結果となりました。
より大きいテーブルでも試してみましたが、どちらの場合でも大きな変化は見られませんでした。
-- 通常のTable
delete from orders
where o_orderkey = 0
;
-- Hybrid Table
delete from customer_hybrid
where c_custkey = 0
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 539ms | 497ms | 529ms | 463ms | 289ms |
Hybrid Table | 168ms | 207ms | 142ms | 136ms | 143ms |
まとめ
トランザクション処理の基本的な操作について、通常のTableとHybrid Tableで比較してみました。
当然ではありますが、Hybrid Tableの方が優位という結果になりました。特に更新処理では大きい差が出ています。
通常のトランザクション処理として考えた場合には、パフォーマンスにやや物足りなさを感じてしまいますが、Hybrid Tableは開発中の機能ですし、今回の検証ではウェアハウスサイズも最小のものしか利用できなかったこともあり、改善の余地は非常にあると考えられます。引き続き今後も検証していきたいと思います。
検証その2: アナリティクス処理
Summitでは、Hybrid TableとTableを組み合わせてデータ分析することができると紹介されていました。実際のユースケースとしても、RDBとDWHのデータを組み合わせて分析したい場合があると思います。そこで、以下の3パターンで、パフォーマンスがどのように変わるかを検証してみます。
- Tableのみから分析
- Hybrid Tableのみから分析
- TableとHybrid Tableを組み合わせて分析
今回は、アジアRegionの顧客の全注文の合計金額を集計するクエリを発行してみます。
Tableのみ / Hybrid Tableのみ から分析
まずは、組み合わせない場合のパフォーマンスについて見てみます。
-- 通常のTableのみで集計
select sum(o_totalprice) from orders o
join customer c on o.o_custkey = c.c_custkey
join nation n on n.n_nationkey = c.c_nationkey
join region r on r.r_regionkey = n.n_regionkey
where r.r_name = 'ASIA'
;
-- Hybrid Tableのみで集計
select sum(o_totalprice) from orders_hybrid o
join customer_hybrid c on o.o_custkey = c.c_custkey
join nation_hybrid n on n.n_nationkey = c.c_nationkey
join region_hybrid r on r.r_regionkey = n.n_regionkey
where r.r_name = 'ASIA'
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
Table | 3.8s | 39ms | 33ms | 46ms | 39ms |
Hybrid Table | 1m18s | 7.4s | 7.7s | 7.5s | 7.3s |
通常のTableのみから構成される集計クエリの場合、2回目以降はQuery Result Cacheが効くようになります。一方、Hybrid Tableを含むクエリの場合にはQuery Result Cacheは効かず、毎回処理が行われているようです。
TableとHybrid Tableを組み合わせて分析
-- ordersのみ、hybrid tableを利用する
select sum(o_totalprice) from orders_hybrid o
join customer c on o.o_custkey = c.c_custkey
join nation n on n.n_nationkey = c.c_nationkey
join region r on r.r_regionkey = n.n_regionkey
where r.r_name = 'ASIA'
;
-- customerのみ、hybrid tableを利用する
select sum(o_totalprice) from orders o
join customer_hybrid c on o.o_custkey = c.c_custkey
join nation n on n.n_nationkey = c.c_nationkey
join region r on r.r_regionkey = n.n_regionkey
where r.r_name = 'ASIA'
;
-- order, customerをhybrid tableにする
select sum(o_totalprice) from orders_hybrid o
join customer_hybrid c on o.o_custkey = c.c_custkey
join nation n on n.n_nationkey = c.c_nationkey
join region r on r.r_regionkey = n.n_regionkey
where r.r_name = 'ASIA'
;
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
---|---|---|---|---|---|
order, customerがhybrid | 7.2s | 5.5s | 7.1s | 6.5s | 6.5s |
orderのみhybrid | 6.7s | 6.3s | 6.0s | 6.3s | 8.7s |
customerのみhybrid | 1.7s | 669ms | 773ms | 236ms | 846ms |
このjoinの中で最も大きいordersテーブル(150万行)がhybridの場合は、クエリはかなり重たいものになってしまいました。一方で、customer(15万行)のみがhybridになっている場合は、クエリのパフォーマンスは大幅に改善されています。
また、Hybrid Tableのデータを分析に使いたい場合のユースケースの多くは、最新データのみHybrid Tableから取得し、主なデータはTableに既に入っている、という状態だと想像されます。そこで、デモデータ内で最新の日付(1998-08-02)のデータを含まないorders_2
テーブルを用意し、最新日のデータのみはHybrid Tableから取得して集計するような以下のクエリも試してみます。
with o as (
select * from orders_2
union all
select * from orders_hybrid where o_orderdate = '1998-08-02'
)
select sum(o_totalprice) from o
join customer_hybrid c on o.o_custkey = c.c_custkey
join nation n on n.n_nationkey = c.c_nationkey
join region r on r.r_regionkey = n.n_regionkey
where r.r_name = 'ASIA'
1回目 | 2回目 | 3回目 | 4回目 | 5回目 |
---|---|---|---|---|
9.5s | 8.8s | 8.4s | 7.5s | 7.9s |
hybridテーブルからは一部のデータしか利用しないため、高速に処理されることを期待していたのですが、残念ながらselect * from orders_hybrid where o_orderdate = '1998-08-02'
の部分の処理が重いため、クエリは高速にはなりませんでした。
まとめ
分析ワークロードでは、通常のテーブルのみのクエリの方が当然高いパフォーマンスを発揮しますが、Hybrid Tableを組み合わせた場合でも、巨大なテーブルでなければ非常に高速に処理できることがわかりました。
アドホックにHybrid TableのデータをDWHのデータと掛け合わせて分析したい、といった用途であれば現段階でも十分実用可能ではないでしょうか。
検証その3: データ同期
では、最後に、Hybrid Tableと通常のTableの間でのデータ同期について検証します。
データ同期の具体的なユースケースとしては、
- RDBのデータをDWHに同期して分析したい
- DWHでデータ集計し、集計結果をRDBに保管したい(ReverseETL, Data Activation)
といったことが想定されます。このようなユースケースにどれくらい対応できるのかを調べるため、以下のような検証を実施しました。
- Hybrid TableからTableへのデータ同期
- TableからHybrid Tableへのデータ同期
Hybrid TableからTableへのデータインサート
3つのテーブルサイズで、パフォーマンスを比較してみます。
-- 25行
insert into nation
select * from nation_hybrid
;
-- 15万行
insert into customer
select * from customer_hybrid
;
-- 150万行
insert into orders
select * from orders_hybrid
;
結果は以下のようになりました。150万行のテーブルでも20秒以内に取り込めます。最小のウェアハウスでこのパフォーマンスなので、非常に高速だと考えて良いのではないでしょうか。また、ETLツールなどを用いずに、クエリ1行でDWHにRDBデータが取り込めるのは革新的ですね...!
nation (25行) | customer (15万行) | order (150万行) |
---|---|---|
460ms | 2.4s | 17s |
なお、CDC(Change Data Capture)で、変更をリアルタイムにDWHに取り込みたいと思うことも多いと思います。Snowflakeには、テーブルの変更を追跡するストリームという機能があり、これを用いるとCDCを実現できます。しかし、残念なことに、現時点ではHybrid Tableに対してストリームを設定することはできませんでした。今後対応してくれることに期待です...!
TableからHybrid Tableへのデータインサート
こちらも、3つのテーブルサイズで、パフォーマンスを比較してみます。
-- 25行
insert into nation_hybrid
select * from nation
;
-- 15万行
insert into customer_hybrid
select * from customer
;
-- 150万行
insert into orders_hybrid
select * from orders
;
結果は以下のようになりました。制約のチェックが入る分、HybridTable->Tableより時間がかかるようになります。また、データ量に対しておおよそ線形にロード時間が伸びているようです。
15万行のbulk insert処理が30秒程度で終わるのであれば、かなり多くのユースケースで実用に耐えるのではないでしょうか。
nation (25行) | customer (15万行) | order (150万行) |
---|---|---|
500ms | 28s | 5m15s |
なお、外部キー制約を外すことで、より高速にロードすることが可能です。
終わりに
今回は、Hybrid Tableの各種パフォーマンスについて、現段階での検証を一通り実施してみました。
TableとHybrid Tableを跨いだ分析クエリやデータ同期については現段階でも実用レベルの完成度になっていると感じました。
一方で純粋なOLTP処理についてはまだ改善の余地があると思われますが、トランザクション負荷の小さいアプリケーションやキャッシュを効かせやすいアプリケーションであれば、問題なく使えそうでした。
総じて、今後の開発の期待がより高まる結果となりました! (※記事公開時点では一部のリージョンでPrivate Previewとして提供)
なお、今回の検証の一部は、以下のYoutube Liveにて紹介しておりますので、こちらの動画も是非ご確認いただければと思います。
Twitterも始めました。Snowflakeに興味のある皆様と繋がれれば嬉しいです!
Discussion