9/29 (木)
Oracle Technology Network
Oracle Technology Networkに申し込んだ。 過去にも申し込んだような気がするが、どのメールアドレスで登録したか失念したのでもう一度申し込む。
9/26 (月)
永年勤続表彰の記念品
永年勤続表彰の記念品として旅行券かカタログギフトを選べるということで、カタログギフトの中のチャリティーを選択する。 日本盲導犬協会に寄付した。
9/24 (土)
[MyWeb][PostgreSQL] 「PostgreSQL プラン・ツリーの概要」を更新
PostgreSQL プラン・ツリーの概要のページを更新し、テーブル結合(Join)系プランの話を追加した。 あとターゲット・リストの話も追加。
9/18 (日)
[MyWeb][PostgreSQL] PostgreSQL の基本データ型とタプルの扱いをまとめる
PostgreSQL のエクステンションを書く際に基本となるPostgreSQL の基本データ型とタプルの扱いを記事としてまとめた。
9/17 (土)
[Movie] キング・オブ・エジプト
『キング・オブ・エジプト』(原題: Gods of Egypt)を観た。 そもそもエジプト神話を借りているだけで古代エジプトの風俗が反映されてないとか色々言われているようだが、アクション大作としては面白く見れた。
9/15 (木)
[MyWeb][PostgreSQL] pg_plan_tree_dot を PostgreSQL 9.6 rc1 に対応させる
PostgreSQL のプランツリーを Graphviz で可視化する pg_plan_tree_dot を PostgreSQL 9.6 rc1 に対応させた。 PostgreSQL 9.5 対応は昨年の10月に行っているので、ほぼ1年ぶりの中改造。
PostgreSQL 9.6 で並列クエリー実行が入り、そのためのデータ構造の変更がいろいろ行われている。 Plan 構造体に plan_node_id や parallel_aware のようなメンバー変数が追加されている。
9/13 (火)
初めての OpenCL for FPGA
Xeon+FPGA の登場に備えて OpenCL で FPGA プログラミングを開始する。 ボードは BittWare 社の S5-PCIe-HQ という奴で Altera Stratix V GX/GS がチップが載っている。
OpenCL Design Examples から Hello World というサンプルを落とす。 コンパイラと論理合成の工程に 40 分かかった後に、Thread #2: Hello from Altera's OpenCL Compiler! と、1行だけ表示する FPGA プログラムが完成した。
wget で HTTPS にアクセスする場合
wget は HTTPS にアクセスする場合、--no-check-certificate と引数を追加する必要がある。 ただしこれを毎回指定するのは面倒。
.wgetrc ファイルに以下の指定を加えるとよい。
check_certificate=off
9/8 (木)
Apache Project の SQL クエリーエンジン
Apache Hive、Apache Pig、Apache Spark と Apache Project には SQL クエリーを処理できるアプリケーションがたくさんあるが、最近でもまだまだ増えているようだ。
- Apache Trafodion
- 分散 SQL-on-Hadoop。ACID トランザクションをサポートしている。OLTP ワークロード向け。
- Apache Tajo
- 分散 SQL-on-Hadoop。 アドホックな分析クエリー、オンライン集約、ETL 向け。
- Apache Calcite
- ストレージへの格納機能を持たない SQL クエリーエンジン。データの格納方法等は任意に実装する。
- Apache Drill
- Google Dremel の OSS で分散アプリケーション実行をサポートするフレームワークで SQL が使える
- Apache Kylin
- 分散 SQL エンジン。OLAP 並びに multi-dimensional analysis 対応。Hive から OLAP Cube を作る。
- Apache Ignite
- JCache(JSR 107)に基づく分散キャッシュ。SQL クエリーで問い合わせができる。
- Apache Sqoop
- RDB から Hadoop へデータを転送する ETL ツール。SQL クエリーが記述できる。
- Apache Zeppelin
- Web ベースのモニタリング・可視化ツール。SQL クエリーが記述できる。
9/7 (水)
[PostgreSQL] scan-all-the-rows aggregation plan node を生成している箇所
PostgreSQL は hashed aggregation を選択された時、テーブルから不要な列までを読み込むことが多い。 PostgreSQL のソースコード内の記述によると、これを scan-all-the-rows aggregation plan node と呼ぶらしい。
例えば T1 という C1、C2、C3 の 3 つの列があるテーブルがあるとする。 このうち C2 を外して、C1 と C3 だけを使って集約を行う。
CREATE TABLE T1(C1 INT, C2 INT, C3 INT); INSERT INTO T1 (C1, C2, C3) SELECT i, i, i FROM generate_series(0, 10000) AS i; ANALYZE T1;
まず hashed aggregation を禁止して、強制的に sorted aggregation にしてみる。 テーブル T1 からは C1 と C3 だけが読み込まれるので、意図した通りの結果である。
SET enable_hashagg = off; dbname=# EXPLAIN (VERBOSE ON, COSTS OFF) SELECT SUM(C3) FROM T1 GROUP BY C1; QUERY PLAN ----------------------------------- GroupAggregate Output: sum(c3), c1 Group Key: t1.c1 -> Sort Output: c1, c3 Sort Key: t1.c1 -> Seq Scan on public.t1 Output: c1, c3 (8 rows)
一方、hashed aggregation を使うと、クエリーには出てこない c2 を勝手に読み込むことになる。
dbname=# EXPLAIN (VERBOSE ON, COSTS OFF) SELECT SUM(C3) FROM T1 GROUP BY C1; QUERY PLAN ----------------------------- HashAggregate Output: sum(c3), c1 Group Key: t1.c1 -> Seq Scan on public.t1 Output: c1, c2, c3 (5 rows)
オプティマイザーの意図としては、テーブル全体をスキャンする SeqScan ノードはテーブルの格納形式のまま上位のノードに返す方が高速である。 そのため SeqScan ノードが C2 を抜くよりも、上位ノードである Agg は全列を受け取り自分が C2 を省く処理をした方が全体として高速になると意図している。 もちろんインデックスで C1 と C3 だけを返す方す IndexOnlyScan が使える場合はその方が高速なので、そのプランが採用される。
問題はこれがオプティマイザーのどの部分で実装されているかだ? オプティマイザーのソースコードをチラッと眺めても、どこで変換しているのか分からなかったがソースコードを丹念に追ってやっと分かった。 問題の箇所は grouping_planner() にある。 これは planner() → subquery_planner() → grouping_planner() の流れで呼ばれる。
- planner()
- subquery_planner()
- grouping_planner()
- subquery_planner()
grouping_planner() は以下のようになる。
static Plan *
grouping_planner(PlannerInfo *root, double tuple_fraction)
{
if (parse->setOperations)
{
// 集約の場合はこちらは選択されない
}
else
{
// こちらが選択される。
final_rel = query_planner(root, sub_tlist,
standard_qp_callback, &qp_extra);
// ...
cheapest_path = final_rel->cheapest_total_path;
// ...
if (use_hashed_grouping || use_hashed_distinct || !sorted_path)
best_path = cheapest_path; // こちらが選択される
else
best_path = sorted_path;
// ...
result_plan = optimize_minmax_aggregates(root,
tlist,
&agg_costs,
best_path);
if (result_plan != NULL)
{
// min()、max() 以外がある場合はこちらは採用されない
}
else
{
result_plan = create_plan(root, best_path); // ☆ // こちらが選択される
// ...
if (use_hashed_grouping)
{
result_plan = (Plan *) make_agg(root, // ★ // こちらが選択される
tlist,
(List *) parse->havingQual,
AGG_HASHED,
&agg_costs,
numGroupCols,
groupColIdx,
extract_grouping_ops(parse->groupClause),
numGroups,
result_plan); // ☆ で設定した result_plan が渡る
}
}
}
return result_plan; // ★で設定した result_plan が返る
}
途中、読み込みテーブルにインデックスがない状態で create_plan(root, best_path) が呼ばれると、一番単純な SeqScan を返す Path が cheapest_path に設定される。 これが best_path = cheapest_path として設定され、さらに create_plan() → create_plan_recurse() → create_scan_plan() と呼ばれる。
- create_plan()
- create_plan_recurse()
- create_scan_plan()
- create_plan_recurse()
create_scan_plan() は以下のようになる。
static Plan * create_scan_plan(PlannerInfo *root, Path *best_path) { if (use_physical_tlist(root, rel)) // こちらが選択される { if (best_path->pathtype == T_IndexOnlyScan) { tlist = copyObject(((IndexPath *) best_path)->indexinfo->indextlist); } else // こちらが選択される { tlist = build_physical_tlist(root, rel); // tlist が値を返す if (tlist == NIL) tlist = build_path_tlist(root, best_path); } } else { tlist = build_path_tlist(root, best_path); } } // }
create_scan_plan() の中で use_physical_tlist() が true で build_physical_tlist() を返す。 これはもっともコストが低い scan-all-the-rows の SeqScan プランノードを返す。
追記
列に対する関数を適用した場合も、SeqScan ノード側ではなく Agg ノード側で適用される。
SET enable_hashagg = off; dbname=# EXPLAIN (VERBOSE ON, COSTS OFF) SELECT SUM(abs(C3)) FROM T1 GROUP BY C1; QUERY PLAN ----------------------------- HashAggregate Output: sum(abs(c3)), c1 Group Key: t1.c1 -> Seq Scan on public.t1 Output: c1, c2, c3 (5 rows)
9/4 (土)
[Movie] グランド・イリュージョン 見破られたトリック
川崎チネチッタで『グランド・イリュージョン 見破られたトリック』(原題:Now You See Me 2)を観る。
9/6 (火)
[Linux] netlink 経由のプロセス生成・消滅の監視
Linux はソケット API に対して AF_NETLINK
を指定することでユーザープログラムとカーネルとの通信を行う netlink インターフェイスを開き、システムのプロパティの取得や設定を行うことができる。
例えばルーティングや SELinux イベント通知、監査(audit)などが netlink 経由で行える。
その中に NETLINK_CONNECTOR
で指定した場合、さらに細かい機能にアクセスできるが、CN_IDX_PROC
を指定するとシステムのプロセスが fork、exec、exit した時などにそれをイベントとして通知して受け取ることができる。
sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
正確には fork(親プロセスのpid/tgidと子プロセスのpid/tgid)、exec(pid/tgid)、ユーザーID変更(pid/tgidと変更後のuid/euid)、グループID変更(pid/tgとgid/egid)、exit(pid/tgidとexitコード)のイベントが取得できる。
参考
- SCOTT JAMES REMNANT | The Proc Connector and Socket Filters
- beware of geek! | linux process monitoring (exec, fork, exit, set*uid, set*gid)