29
中国 DB 勉強会 (2015-01-31) Lighting-Talk インガオホー! jsonb + postgres_fdw ぬこ@横浜 (@nuko_yokohama)

Lt ingaoho-jsonb+postgeres fdw

Embed Size (px)

Citation preview

Page 1: Lt ingaoho-jsonb+postgeres fdw

中国 DB 勉強会(2015-01-31)

Lighting-Talk

インガオホー!jsonb + postgres_fdw

ぬこ@横浜 (@nuko_yokohama)

Page 2: Lt ingaoho-jsonb+postgeres fdw

ドーモ、勉強会出席者の

ミナ=サンぬこ@横浜です某通信系暗黒ソフトウェアコーポで働いてる

おおむね善良で社会的に害はないサラリマン!

Page 3: Lt ingaoho-jsonb+postgeres fdw

今日はマツエ殺伐都市へ

お呼び頂きアリガトネ!

Page 4: Lt ingaoho-jsonb+postgeres fdw

最近、 NJSLYR を読み始めたニュービーです。

なのでこの LT は NJSLYR 的なコトダマ混入成分過多!そして、このスライドは頭のう指数が大幅低下!

コワイ!

Page 5: Lt ingaoho-jsonb+postgeres fdw

本題

Page 6: Lt ingaoho-jsonb+postgeres fdw

JSONB データ型とpostgres_fdw の組み合わせ!

ちょっとやめないか

Page 7: Lt ingaoho-jsonb+postgeres fdw

JSONB データ型

・・・については今日の発表やPGCon.jp/JPUG 勉強会など

おおよそ過去の発表で既に拝聴

Page 8: Lt ingaoho-jsonb+postgeres fdw

postgres_fdwhttp://www.postgresql.jp/document/9.3/html/postgres-fdw.html

主開発者の花田=サンとPostgreSQL コミュニティの

タツジンの見事なワザマエが光る一品。

実際スゴイ!

Page 9: Lt ingaoho-jsonb+postgeres fdw

postgres_fdw外部の PostgreSQL サーバに格納されたデータを

自分の DB 内のテーブルであるかのようにアクセスするために使用する、外部データラッパ

類似モジュールとして dblink があるが、postgres_fdw のほうが、より自然なクエリが書ける。

参照だけでなく、更新 (insert/update/delete) も可。

PostgreSQL 9.3 からサポートされている。と、古事記 PostgreSQL 文書に書かれている。

Page 10: Lt ingaoho-jsonb+postgeres fdw

例えばpostgres_fdw を使って

別データベース上の表との結合ヤッター!

Page 11: Lt ingaoho-jsonb+postgeres fdw

しかし

Page 12: Lt ingaoho-jsonb+postgeres fdw

通常の表で使える機能が外部表で全て使える

わけではない。備えよう。

Page 13: Lt ingaoho-jsonb+postgeres fdw

その 1COPY

イヤーッ!

Page 14: Lt ingaoho-jsonb+postgeres fdw

グワーッ!foo=# COPY test FROM '/tmp/json.txt';ERROR: cannot copy to foreign table "test"foo=#

外部テーブルに直接 COPY はできない。

リモートサーバ

外部表

ローカルサーバ

JSON データ COPY

Page 15: Lt ingaoho-jsonb+postgeres fdw

COPY の問題は以下のジツを使って回避可能

1. リモートテーブルに直接 COPY2. INSERT 文を使用

3. file_fdw+ バルク INSERT(3 . の方法の詳細は次ページで説明)

備えよう。

Page 16: Lt ingaoho-jsonb+postgeres fdw

file_fdw+ バルク INSERTこんなアトモスフィアなシェル作成!

#!/bin/shDBNAME=$1FOREIGN_TABLE_ARG=$2LOAD_FILE_NAME=$3LOAD_TABLE_NAME=$4

CREATE_SERVER_SQL="CREATE SERVER __cp_server FOREIGN DATA WRAPPER file_fdw"psql ${DBNAME} -c "${CREATE_SERVER_SQL}"

CREATE_FOREIGN_TABLE_SQL="CREATE FOREIGN TABLE __cp_table ( ${FOREIGN_TABLE_ARG} ) SERVER __cp_server OPTIONS (filename '${LOAD_FILE_NAME}')"psql ${DBNAME} -c "${CREATE_FOREIGN_TABLE_SQL}"

INSERT_SQL="INSERT INTO ${LOAD_TABLE_NAME} (SELECT data FROM __cp_table )"psql ${DBNAME} -c "${INSERT_SQL}"

DROP_FOREIGN_TABLE_SQL="DROP FOREIGN TABLE __cp_table"psql ${DBNAME} -c "${DROP_FOREIGN_TABLE_SQL}"

DROP_SERVER_SQL="DROP SERVER __cp_server"psql ${DBNAME} -c "${DROP_SERVER_SQL}"

contrib/file_fdw の外部サーバ / 外部表を定義外部表を SELECT で全件検索した結果を

INSERT 文に流し込む。最後に外部表と外部サーバを爆発四散!

Page 17: Lt ingaoho-jsonb+postgeres fdw

file_fdw+ バルク INSERT前ページのシェルを実行!

$ ./fdw_cp foo "data jsonb" "/tmp/json.txt" "test"CREATE SERVERCREATE FOREIGN TABLEINSERT 0 100000DROP FOREIGN TABLEDROP SERVER$

ゴウランガ!COPY で使うファイルをそのまま使って

外部表へロード可能!(COPY より遅いのは仕方がない。いいね?)

このシェルは postgres_fdw 専用というわけでなく挿入操作が可能な FDWなら使用重点!

Page 18: Lt ingaoho-jsonb+postgeres fdw

その 2TRUNCATEイヤーッ!

Page 19: Lt ingaoho-jsonb+postgeres fdw

グワーッ!外部テーブルに対する

TRUNCATEはどの FDW でもできないっぽい。

ざんねんながらリモートの実表に TRUNCATE 必須!

Page 20: Lt ingaoho-jsonb+postgeres fdw

その 3外部テーブル内の

JSONB に対する検索

これは説明重点。

Page 21: Lt ingaoho-jsonb+postgeres fdw

例えば、外部テーブルのソースとなるサーバに以下のような

JSONB カラムを持つtest テーブルがあるとする。

確かにあるのだ!

bar=# \d test Table "public.test" Column | Type | Modifiers --------+-------+----------- data | jsonb | Indexes: "test_id_idx" btree ((data ->> 'id'::text)) "test_idx" gin (data)

Page 22: Lt ingaoho-jsonb+postgeres fdw

ローカルな問い合わせならbtree 式インデックスも

gin インデックスも使える。bar=# EXPLAIN SELECT * FROM test WHERE data->>'id' = '10000'; QUERY PLAN ------------------------------------------------------------------------- Index Scan using test_id_idx on test (cost=0.42..8.44 rows=1 width=70) Index Cond: ((data ->> 'id'::text) = '10000'::text)(2 rows)

bar=# EXPLAIN SELECT * FROM test WHERE data @> '{"id":10000}'; QUERY PLAN -------------------------------------------------------------------------- Bitmap Heap Scan on test (cost=28.77..336.47 rows=100 width=70) Recheck Cond: (data @> '{"id": 10000}'::jsonb) -> Bitmap Index Scan on test_idx (cost=0.00..28.75 rows=100 width=0) Index Cond: (data @> '{"id": 10000}'::jsonb)(4 rows)

あからさまにインデックス検索なのだ!

Page 23: Lt ingaoho-jsonb+postgeres fdw

しかし外部テーブル経由だと

Page 24: Lt ingaoho-jsonb+postgeres fdw

@> 演算子 { キー : 値 } の場合WHERE 句を pushdown して、

リモート側でも GIN インデックスを使用foo=# EXPLAIN ANALYZE SELECT * FROM test WHERE data @> '{"id":10000}'; QUERY PLAN -------------------------------------------------------------- Foreign Scan on test (cost=100.00..128.29 rows=1 width=32) (actual time=0.579..0.579 rows=1 loops=1) Planning time: 0.052 ms Execution time: 0.867 ms(3 rows)

Time: 1.204 ms

外部テーブルから返却された時点で1件になっていることに注目重点な!

実際速い!

Page 25: Lt ingaoho-jsonb+postgeres fdw

->>' キー ' 演算子 値 の場合WHERE 句は pushdown されず、

リモート側でフルスキャン全件取得!アイエエエ!フルスキャン!

フルスキャンナンデ!foo=# EXPLAIN ANALYZE SELECT * FROM test WHERE data->>'id' = '10000'; QUERY PLAN ---------------------------------------------------------------------- Foreign Scan on test (cost=100.00..159.93 rows=7 width=32) (actual time=31.028..273.480 rows=1 loops=1) Filter: ((data ->> 'id'::text) = '10000'::text) Rows Removed by Filter: 99999 Planning time: 0.046 ms Execution time: 273.581 ms(5 rows)

そして外部テーブルからは全件 (10万件 ) 返却されている!あからさまにフルスキャンなのだ!ヤンナルネ・・・

実際遅い!

Page 26: Lt ingaoho-jsonb+postgeres fdw

postgres_fdw 外部テーブルに渡すWHERE 句の書き方によって

Pushdwon されたりされなかったりする。

おかしいと思いませんか?あなた

Page 27: Lt ingaoho-jsonb+postgeres fdw

古事記 PostgreSQL 文書にはこう書かれている

F.31.4. リモート問合せの最適化

外部サーバからのデータ転送量を削減するため、postgres_fdw はリモート問合せを最適化しようと試みます。 これは問い合わせのWHERE 句をリモートサーバに送出する事、およびクエリで必要とされていないカラムを取得しない事により行われます。 問い合わせの誤作動のリスクを下げるため、ビルトインのデータ型、演算子、関数だけを用いたものでない限り、リモートサーバにWHERE 句は送出されません。また、WHERE 句で使われる演算子と関数は IMMUTABLEでなければなりません。

カラム ->>' キー名 ' への比較演算だとダメっぽい?無視できぬ記述だ!

Page 28: Lt ingaoho-jsonb+postgeres fdw

要するに、特定の条件式がPushdown されない問題は

「これはバグではない。いいね?」「アッハイ」

JSON 型 /XML 型等と postgres_fdw は相性は良くないかも・・・

Page 29: Lt ingaoho-jsonb+postgeres fdw

ということでpostgres_fdw は便利ですが

使用時には注意重点な。という話でした。オタッシャデー!