jsonbでpgbench
そういえば、今までなんでやってなかったのかな、と思っていたけどpgbenchのカスタムクエリ機能を使って、pgbenchデータをJSONB化したテーブルにアクセスして、どのくらいの性能が出るのかを試してみた。
今回は、検索キーをbtree式インデックスで検索する方式と、ginインデックスで検証する方式の二通りを試してみた。
準備
pgbenchでスケール=10のデータをロードしておき、そのデータから以下のようなSQLでJSONデータを作成する。
COPY (SELECT row_to_json(pgbench_accounts.*) FROM pgbench_accounts) TO '/tmp/accounts.txt' ; COPY (SELECT row_to_json(pgbench_branches.*) FROM pgbench_branches) TO '/tmp/branches.txt' ; COPY (SELECT row_to_json(pgbench_tellers.*) FROM pgbench_tellers) TO '/tmp/tellers.txt' ; COPY (SELECT row_to_json(pgbench_history.*) FROM pgbench_history) TO '/tmp/history.txt' ;
まあ、pgbench_historyは最初は0件だけど、いちおー作っておく。
btree式インデックス方式
こんな感じでテーブルの定義とインデックスを定義し、スケール10(pgbench_accountsが100万件)のデータをロードして、btree式インデックスを設定しておく。
テーブル定義とインデックス定義
[nuko@localhost jsonb]$ cat jsonb_bench_i.sh #!/bin/sh DBNAME=bench_jsonb cp accounts.txt /tmp cp branches.txt /tmp cp history.txt /tmp cp tellers.txt /tmp dropdb ${DBNAME} createdb ${DBNAME} psql ${DBNAME} -c "CREATE TABLE pgbench_accounts (data jsonb);" psql ${DBNAME} -c "CREATE TABLE pgbench_branches (data jsonb);" psql ${DBNAME} -c "CREATE TABLE pgbench_tellers (data jsonb);" psql ${DBNAME} -c "CREATE TABLE pgbench_history (data jsonb);" psql ${DBNAME} -c "COPY pgbench_accounts (data) FROM '/tmp/accounts.txt';" psql ${DBNAME} -c "COPY pgbench_branches (data) FROM '/tmp/branches.txt';" psql ${DBNAME} -c "COPY pgbench_tellers (data) FROM '/tmp/tellers.txt';" psql ${DBNAME} -c "COPY pgbench_history (data) FROM '/tmp/history.txt';" psql ${DBNAME} -c "CREATE INDEX pgbench_accounts_pkey ON pgbench_accounts USING btree (((data->>'aid')::int));" psql ${DBNAME} -c "CREATE INDEX pgbench_branches_pkey ON pgbench_branches USING btree (((data->>'bid')::int));" psql ${DBNAME} -c "CREATE INDEX pgbench_tellers_pkey ON pgbench_tellers USING btree (((data->>'tid')::int));" rm /tmp/accounts.txt rm /tmp/branches.txt rm /tmp/history.txt rm /tmp/tellers.txt [nuko@localhost jsonb]$
実行スクリプト
この状態で以下の2つのファイルを作成して、pgbenchのカスタムクエリモードで実行する。
どちらもpgbenchの参照のみ/参照更新ありで実行されるクエリをベースにしている。
- 参照のみ
[nuko@localhost jsonb]$ cat bench-jsonb-select.sql \set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -5000 5000 BEGIN; SELECT data->>'abalance' FROM pgbench_accounts WHERE (data->>'aid')::int = :aid; END; [nuko@localhost jsonb]$
- 更新あり
[nuko@localhost jsonb]$ cat bench-jsonb.sql \set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -5000 5000 BEGIN; UPDATE pgbench_accounts SET data = json_build_object('aid', (data->>'aid')::int, 'bid', (data->>'bid')::int, 'abalance', (data->>'abalance')::int + :delta , 'filler', data->>'filler')::jsonb WHERE (data->>'aid')::int = :aid; SELECT data->>'abalance' FROM pgbench_accounts WHERE (data->>'aid')::int = :aid; UPDATE pgbench_tellers SET data = json_build_object('tid', (data->>'tid')::int, 'bid', (data->>'bid')::int, 'tbalance', (data->>'tbalance')::int + :delta, 'filler', data->>'filler')::jsonb WHERE (data->>'tid')::int = :tid; UPDATE pgbench_branches SET data = json_build_object('bid', (data->>'bid')::int, 'bbalance', (data->>'bbalance')::int + :delta, 'filler', data->>'filler')::jsonb WHERE (data->>'bid')::int = :bid; INSERT INTO pgbench_history (data) VALUES ( json_build_object('tid', :tid, 'bid', :bid, 'aid', :aid, 'delta', :delta, 'mtime', CURRENT_TIMESTAMP, 'filler', ' ')::jsonb); END; [nuko@localhost jsonb]$
更新がちょい長くて如何にも遅そうなんだけど仕方がない。
ginインデックス版
今度はginインデックスと条件判定に @> を使うパターン。
テーブル定義とインデックス定義
[nuko@localhost jsonb]$ cat jsonb_bench_gin_i.sh #!/bin/sh DBNAME=bench_jsonb cp accounts.txt /tmp cp branches.txt /tmp cp history.txt /tmp cp tellers.txt /tmp dropdb ${DBNAME} createdb ${DBNAME} psql ${DBNAME} -c "CREATE TABLE pgbench_accounts (data jsonb);" psql ${DBNAME} -c "CREATE TABLE pgbench_branches (data jsonb);" psql ${DBNAME} -c "CREATE TABLE pgbench_tellers (data jsonb);" psql ${DBNAME} -c "CREATE TABLE pgbench_history (data jsonb);" psql ${DBNAME} -c "COPY pgbench_accounts (data) FROM '/tmp/accounts.txt';" psql ${DBNAME} -c "COPY pgbench_branches (data) FROM '/tmp/branches.txt';" psql ${DBNAME} -c "COPY pgbench_tellers (data) FROM '/tmp/tellers.txt';" psql ${DBNAME} -c "COPY pgbench_history (data) FROM '/tmp/history.txt';" psql ${DBNAME} -c "CREATE INDEX pgbench_accounts_gin ON pgbench_accounts USING gin (data);" psql ${DBNAME} -c "CREATE INDEX pgbench_branches_gin ON pgbench_branches USING gin (data);" psql ${DBNAME} -c "CREATE INDEX pgbench_tellers_gin ON pgbench_tellers USING gin (data);" rm /tmp/accounts.txt rm /tmp/branches.txt rm /tmp/history.txt rm /tmp/tellers.txt [nuko@localhost jsonb]$
実行スクリプト
- 参照のみ
\set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -5000 5000 BEGIN; SELECT data->>'abalance' FROM pgbench_accounts WHERE data @> json_build_object('aid', :aid )::jsonb; END;
- 更新あり
\set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -5000 5000 BEGIN; UPDATE pgbench_accounts SET data = json_build_object('aid', (data->>'aid')::int, 'bid', (data->>'bid')::int, 'abalance', (data->>'abalance')::int + :delta , 'filler', data->>'filler')::jsonb WHERE data @> json_build_object('aid', :aid )::jsonb; SELECT data->>'abalance' FROM pgbench_accounts WHERE data @> json_build_object('aid', :aid )::jsonb; UPDATE pgbench_tellers SET data = json_build_object('tid', (data->>'tid')::int, 'bid', (data->>'bid')::int, 'tbalance', (data->>'tbalance')::int + :delta, 'filler', data->>'filler')::jsonb WHERE data @> json_build_object('tid', :tid )::jsonb; UPDATE pgbench_branches SET data = json_build_object('bid', (data->>'bid')::int, 'bbalance', (data->>'bbalance')::int + :delta, 'filler', data->>'filler')::jsonb WHERE data @> json_build_object('bid', :bid )::jsonb; INSERT INTO pgbench_history (data) VALUES ( json_build_object('tid', :tid, 'bid', :bid, 'aid', :aid, 'delta', :delta, 'mtime', CURRENT_TIMESTAMP, 'filler', ' ')::jsonb); END;
比較用
通常のデータ型を使うpgbench用のスクリプト。今回は、このファイルをカスタムクエリモードで動かす。
[nuko@localhost jsonb]$ cat ../bench bench-select.sql bench.sql [nuko@localhost jsonb]$ cat ../bench.sql \set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -5000 5000 BEGIN; UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; SELECT abalance FROM pgbench_accounts WHERE aid = :aid; UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); END; [nuko@localhost jsonb]$