Webscale PostgreSQL - JSONB and Horizontal Scaling Strategies
Postgresql advent calender 2014 using jsonb by ecpg
-
Upload
toshi-harada -
Category
Technology
-
view
865 -
download
2
Transcript of Postgresql advent calender 2014 using jsonb by ecpg
みなさん、こんにちは
このスライドはPostgreSQL Advent Calender 20147 日目のエントリ用のスライドです。
先日 (12/5) 開催されたPostgreSQLカンファレンスで
JSONB 型について発表しましたが、(スライドはこちら)
その発表から削った小ネタをAdvent Calender に転用しますw
埋め込み SQL(Embedded SQL)
手続き型言語に SQL を埋め込んでデータベースアクセスを可能にする手法
(http://ja.wikipedia.org/wiki/%E5%9F%8B%E3%82%81%E8%BE%BC%E3%81%BFSQL)
[nuko@localhost ecpg]$ cat sample.pgc #include <stdio.h>#include <stdlib.h>
intmain (void){
EXEC SQL CONNECT TO test USER nuko;
/* TRUNCATE TABLE sample */EXEC SQL BEGIN TRANSACTION;
EXEC SQL TRUNCATE test;EXEC SQL COMMIT;EXEC SQL DISCONNECT;
return (0);}
[nuko@localhost ecpg]$
C 言語の埋め込み SQL 例( TRUNCATE TABLE の実行)
"EXEC SQL“ で始まる行は埋め込み SQL として
SQL そのものを記述できる
PostgreSQL には、埋め込みSQL を処理するプリコンパイラ「 ecpg 」がコア機能として
組み込まれている。(http://www.postgresql.jp/document/9.3/html/ecpg.html)
先ほどの sample.pgc をecpg にかけると
sample.c ファイルが生成される
$ ls sample*sample.pgc$ ecpg sample.pgc $ ls sample*sample.c sample.pgc$
こんな感じの C コードに展開$ cat sample.c /* Processed by ecpg (4.10.0) *//* These include files are added by the preprocessor */#include <ecpglib.h>#include <ecpgerrno.h>#include <sqlca.h>/* End of automatic include section */
#line 1 "sample.pgc"#include <stdio.h>#include <stdlib.h>
intmain (void){
{ ECPGconnect(__LINE__, 0, "test" , "nuko" , NULL , NULL, 0); }#line 7 "sample.pgc"
/* TRUNCATE TABLE sample */{ ECPGtrans(__LINE__, NULL, "begin transaction");}
#line 10 "sample.pgc"
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate test", ECPGt_EOIT, ECPGt_EORT);}#line 11 "sample.pgc"(中略)
return (0);}
で、生成された C ソースをC コンパイラにかける。
ecpg ヘッダファイル格納先を -I で指定ecpg ライブラリ (libecpg) をリンク時に指定
$ cc -o sample -I${HOME}/pgsql/include -L${HOME}/pgsql/lib -lecpg sample.c$
これで完成!
PostgreSQL における埋め込み SQL の扱い ( 適当 )
西暦 PostgreSQLバージョン
PostgreSQLでの対応
世界の動き
1998 年 6.3 ecpg の初リリース アントニオ猪木がドン・フライと引退試合
2000 年 7.0 メモリリーク対応 PlayStation2 発売
2002 年 7.2 EXECUTE 文対応配列対応の改善
Xbox 日本国内で発売
2003 年 7.4 ecpg と ecpglib のスレッドセーフ化
新幹線 100系が運行終了
2005 年 8.0 SET DESCRIPTOR 対応 愛知万博
8.1 \x16 進数エスケープのサポート
PostgreSQL における埋め込み SQL の扱い ( 適当 )
西暦 PostgreSQLバージョン
PostgreSQLでの対応
世界の動き
2006 年 8.2 SHOW コマンド対応リグレッション試験対応
冥王星が惑星から除外
2008 年 8.3 V3 Frontend/backend protocol の採用
0 系新幹線運用終了
2009 年 8.4 ecpg パーサがサーバパーサから自動生成
1 兆ジンバブエ・ドルの発行
2010 年 9.0 SQLDA サポート はやぶさ、地球に帰還
2011 年 9.1 WHERE CURRENT OF 句の改善
おせち事件
2014 年 9.4 C スタイルコメントのネスト対応(?)
WindowsXP おわた
※要は最近も開発継続中ということ。
他 DBMS での対応DBMS COBOL C C++ FORTRAN Pascal
Oracle ○ ○ ○ ○ ○PostgreSQL ○ △DB2 ○SQLServer(以前)
○
Informix ○
Oracle はマメにサポートしてるなあ。PostgreSQL の C++ 対応は不完全
つまり、 Oracle の Pro*C で作ったアプリケーションは
PostgreSQL ecpg への移植が容易? _ _ _ / ´ = : ミ ´ 二 . ヾ\ / ' / '´r ー = 、ヽ . ヽ 、ヽ i / 〃 , イ | | |_L| l l 埋め込み SQL は誰でもウェルカム |.l.l ル '__ リヽ ヘ l_N ヽ !.l | PostgreSQL でも Oracle でもお好きなものを | |. バ ̄ o` ´o  ̄ ,"|l | どうぞお気になさらず. レ1  ̄ 〈 |:  ̄ !`| ご自由にお楽しみください ド」 、ー -----‐ ァ ,l イ ! _,,... -‐| l ト、` ¨ 二 ¨´ ,. イ .l l ー - ...._ , ィ ''"´:::::::::::::::| l.l :::: ヽ、 __, .::´ :l.l |::::::::::::::::: ` ¨l ヽ r' つ. /:::|:::::::::::::::::::::::W \ ::::::::::: / l ル :::::::::::::::::::::::|::: ヽ / ∟、 -‐'' つ /:::::: |::::::::::::::::::::::::l. \ / .l::::::::::::::::::::::::|:::::: ヽ ,.< )ヽヾニニ⊃. /:::::::::::|:::::::::::::::::::::::::l /\ .l::::::::::::::::::::::::|:::::::::: ヽ /\\ i l ニ二⊇/:::::::::::::::|:::::::::::::::::::::::::l /\ _ /\ .!::::::::::::::::::::::::|:::::::::::::: ヽ / :::::::::::: \ . ゝ -─' ー -- ':::::::::::::::::::|::::::::::::::::::::::::: l ハ /:::::::::::::::::::::::::|:::::::::::::::::: \ / :::::::::::::::::::: /:::::::::::::::::: l:::::::::::::::::::::::::::! ./ ヽ ./::::::::::::::::::::::::::|:::::::::::::::::::: / :::::::::::::::::::: /ヽ ::::::::::::::; イ :::::::::::::::::::::::::::V V:::::::::::::::::::::::::::: ト、 :::::::::::::/:::::::::::::::::::::: /:::::::::::::::/ |:::::::::::::::::::::::::::: ヽ ./::::::::::::::::::::::::::::::| ヽ :::::::::::::::::::::::::::: /::::::::::::/ | :::::::::::::::::::::::::::::∨::::::::::::::::::::::::::::::::| ヽ :::::::::::::::::: /_ : / |:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::| \_ : /
そんなに甘くはない。 , -‐; z ..__ _丿 / ゙̄ヽ′ ニ‐ - 、\ \ ところがどっこい Z ´// , ヘ .∧ ヽ \ヽ ゝ ヽ ‥‥‥‥ /, / , リ v ヘ lヽ\ヽヽ .| ノ 夢じゃありません / イル _- 、 ij~ ハにヽ ,, \ `| < ‥‥‥‥!. N⌒ ヽヽ / / ̄リ :| l l | ` ) ト、 _e. 〉 u ' e _ ノノ |.l l | ∠ . 現実です | 、< 、 ij _,¨ 、イ || ト、 | ヽ ‥‥‥!. | ドエエエ「 -┴''´|.|L 八 ノ - 、 これが現実‥! l. ヒ _ ー -r- ー ' スソ | l トゝ、 .__ | ,. - 、 _,,. -‐ ''" トヽエエエエ ! ゝ '´. イ i l;;;;:::::::::::`:: ー / ハ :::::::::::::::::::::| l \ー一 _v~'´ j ,1;;;;;;:::::::::::::::::::. /:::;l::::::::::::::::::::;W1;;; 下、 / l ル ' !;;;;;;;;;:::::::::::::::: /:::::;;; l :::::::::::::::::;;;;;;;;;;;;;;;|: : X : : : : : |;;;;;;;;;;;;;;:::::::::::: /:::::;;;;;;|:::::::::::::::;;;;;;;;;;;;;;;;|/: : > 、 : : :|;;;;;;;;;;;;;;;:::::::::::
Oracle 独自拡張多すぎぃ!(動的 SQL の扱いなど)
【閑話休題 昔話】
そういえば某社の入社直後にプリコンパイラの概念も知らずホスト言語の COBOL も知らず移植元の PL/I ベースの言語も
知らないままに、C 言語でプリコンパイラ作成の一部を
やらされたのは良い思い出
$ cat sample.pgc #include <stdio.h>#include <stdlib.h>
intmain (void){
EXEC SQL CONNECT TO test USER nuko;
/* TRUNCATE TABLE sample */EXEC SQL BEGIN TRANSACTION;
EXEC SQL TRANCATE test;EXEC SQL COMMIT;EXEC SQL DISCONNECT;
return (0);}
$ ecpg sample.pgc sample.pgc:11: ERROR: unrecognized data type name "TRANCATE"$
プリコンパイル時の構文チェックの例
TRUNCATE 文のスペルミス
プリコンパイル時にエラーチェックしてくれる
intmain (void){EXEC SQL BEGIN DECLARE SECTION; // Host variable VARCHAR insert_data[1024]; VARCHAR id[16]; VARCHAR name[128]; VARCHAR age[16]; // null indicator int age_ind;
EXEC SQL END DECLARE SECTION;
int i;
JSONB アクセス用のホスト変数
可変長テキストの場合はVARCHAR という特殊な記法で宣言する
これはホスト変数じゃない
識別子用変数(後述)
ecpg で JSONB を扱う場合は VARCHAR を使うことになる。
char* values[3] = { "{\"id\":1, \"name\": {\"first\": \"Oleg\"}, \"distribute\": [\"GIN\", \"hstore\", \"json\", \"jsonb\"]}", "{\"id\":2, \"age\": 59, \"name\": {\"last\": \"Lane\", \"first\": \"Tom\"}}", "{\"id\":3, \"name\": {\"nickname\": \"nuko\"}, \"distribute\": [\"ksj\", \"neo4jfdw\"]}"};
(中略) VARCHAR insert_data[1024];(中略)
for (i=0; i<=2; i++) { insert_data.len = strlen(values[i]); strcpy(insert_data.arr, values[i]); EXEC SQL INSERT INTO jsonb_t VALUES ( :insert_data ); }
ホスト変数を使って JSONB を INSERT
長さ (len) とデータ実体 (arr) を事前にセットする
SQL内でホスト変数を使うときには
”:” を前につける
/* select jsonb data (use cursor) */ EXEC SQL DECLARE cur CURSOR FOR SELECT data->>'id', data->>'name', data->>'age' FROM jsonb_t;
EXEC SQL OPEN cur; while (true) { EXEC SQL FETCH NEXT FROM cur INTO :id, :name, :age:age_ind; if (sqlca.sqlcode > 0) break;
if ( age_ind < 0) { // "age" is null printf("id=%s, name=%s\n", id.arr, name.arr); } else { // "age" is not null printf("id=%s, name=%s, age=%s\n", id.arr, name.arr, age.arr); } } EXEC SQL CLOSE cur;
ホスト変数を使って JSONB を SELECT(カーソルの細かい説明は割愛。すいません)
JSONB 演算子を使ったSELECT 文でカーソルを定義
FETCH文内にホスト変数を記述
指示子はホスト変数の後ろに記述する
値参照時にはarr をつける
/* select jsonb data (use cursor) */ EXEC SQL DECLARE cur CURSOR FOR SELECT data->>'id', data->>'name', data->>'age' FROM jsonb_t;
EXEC SQL OPEN cur; while (true) { EXEC SQL FETCH NEXT FROM cur INTO :id, :name, :age:age_ind; if (sqlca.sqlcode > 0) break;
if ( age_ind < 0) { // "age" is null printf("id=%s, name=%s\n", id.arr, name.arr); } else { // "age" is not null printf("id=%s, name=%s, age=%s\n", id.arr, name.arr, age.arr); } } EXEC SQL CLOSE cur;
指示子について(主に null の判別のために使う変数)
指示子変数が負の値ならnull である 指示子はホスト変数の
後ろに記述する
$ ecpg jsonb.pgc$ cc -o jsonb -I${HOME}/pgsql/include -L${HOME}/pgsql/lib -lecpg jsonb.c$ ./jsonb id=1, name={"first": "Oleg"}id=2, name={"last": "Lane", "first": "Tom"}, age=59id=3, name={"nickname": "nuko"}$
プリコンパイル・コンパイル・実行
埋め込み SQL でも JSONB はフツーに使えました!