postgresql

pgbench

Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 4.56 2.36 2.36 7000 0.00 0.00 OpernameGetCandidates 4.09 4.47 2.11 7001 0.00 0.00 yyparse 3.99 6.53 2.06 1419187 0.00 0.00 Alloc…

btree index (9)

btree indexの構築 create index文でindexを作成するとき、btbuildが実行される。 btree indexの作成方法は以下の2通りがある。 (1)テーブルのデータをソートしてから、インデックスを構築する (2)テーブルのデータを順番に、インデックスに挿入する通常は(…

btree index (8)

_bt_compare scankeyとindex tupleを比較する。 index_getattrでindex tupleのデータを取得し,FunctionCall2で比較を実行する。 FunctionCall2には,異なるデータ型の比較をサポートするために,先頭の引数にindex tupleのデータを渡さなければいけないとい…

btree index (7)

_bt_findsplitloc btree indexのページを分割するとき,どの位置で左右に分割するかを決める。 先頭のアイテムから順にサイズを取得し,そのアイテムを左のページに追加した場合の左右の空き領域を計算する。次に_bt_checksplitlocを実行して左右の空き領域…

btree index (6)

meta page btree indexの先頭ページにはmeta pageというデータがおかれ,rootノードの位置などを記録する。(btreeではrootページが分割されるときrootページが移動するので,その位置をmeta pageで管理している) typedef struct BTMetaPageData { uint32 btm…

btree index (5)

_bt_moveright 例えば,更新トランザクション(UPD-Tr)と検索トランザクション(SEL-Tr)が,以下のように並行動作した場合, UPD-Tr: 親ノードP0を検索し,リーフページP1のポインタを取得 SEL-Tr: 親ノードP0を検索し,リーフページP1のポインタを取得 UPD-Tr…

btree index (4)

_bt_addtup ページの指定した位置に,BTItemを登録する。 offsetを指定してPageAddItemを実行する。 PageAddItem ページにItemを登録する。 PageAddItemはb-tree以外にも,tupleや他のindexのアイテムを登録するために 実行される。OffsetNumberでページ内の…

btree index (3)

_bt_insertonpg 指定したページにBTItemを登録する。 non-unique indexで重複したキーを登録する場合,以下のルールで登録する場所を決めている。(1)指定したページに登録できる場合:同じキーの先頭に挿入する。(新しく登録するアイテムが先頭になる)(2)指…

btree index (2)

_bt_doinsert btreeへBTItemを登録する。public interfaceのbtbuildやbtinsertから実行される。 (1)_bt_mkscankeyでインデックスのデータを比較するためのScanKeyを生成する (2)_bt_searchでBTItemを登録する,先頭のリーフページを取得する (3)Read lockを…

btree index (1)

Indexがあるテーブルにinsert文を実行すると、indexに登録するためにbtinsertが実行される。 #0 btinsert (fcinfo=0xbffeb8a0) at nbtree.c:225 #1 0x08289103 in FunctionCall6 (flinfo=0x83f10b0, arg1=1099692112, arg2=3221142352, arg3=3221142320, arg…

check_stack_depth

関数呼び出しが深くなるたび、各関数のローカル変数などを割り当てるためにスタック領域を消費する。再帰コールが大量に発生するなどの理由で、スタックを使い切ってしまうとSIGSEGVエラーになりプロセスが終了してしまうため、そうなる前にERRORを発生させ…

parser/keywords.c

ScanKeywords キーワードの配列。 selectなどのキーワードが列記してある。バイナリサーチで検索するためアルファベット順に記述されている。 ScanKeywordLookup() 文字列がキーワードに一致するか調べる。parserから実行される。 一致するキーワードが見つ…

データ型による性能の違い

テストテーブル作成 create table int4_test(d int4); create table int8_test(d int8); create table float4_test(d float4); create table float8_test(d float8); create table numeric_test(d numeric); create table text_test(d text); create table v…

Cache last known per-tuple offsets to speed long tuple accessを実装したときのメモ

カラム数が多いテーブルをjoinするとき,heaptuple.cのnocachegetattr()に負荷がかかる。 390行目付近のfor()ループで,カラムの先頭から調べてるので,カラム数が多いほど負荷が高くなる。ExecProject() -> ExecTargetList() -> ExecEvalExpr() -> ExecEval…

regexp_replaceを実装したときのメモ

1.backend/regex/regexec.cのpg_regexec()で,検索開始位置を設定できるように拡張する。 (これがないと,2箇所目以降の置換開始位置を決められない)○backend/regex/regexec.c ・pg_regexecに検索開始位置を指定する引数を増やす(size_t search_start)。 ・p…

AllocSetResetの高速化

AllocSetContextにisResetという変数が追加された。これはcontextの初期化やリセット時にtrueに設定され、contextからメモリを確保したときにfalseになる。 bool isReset; /* T = no space alloced since last reset */AllocSetResetではisResetがfalseのと…

WAL(3)

heap_insertのときのブロックのバックアップ insertするタプルがブロックの最初のタプルだった場合,ブロックのバックアップは行わない。(rdata[1].buffer = rdata[2].buffer = InvalidBuffer;でクリアしている) checkpointを発生させる方法 superuserでログ…

optimizer: havingの最適化

subquery_plannerで,havingの条件をwhereに移動する最適化を実行している。(planner.c:294-346行目) 以下の3パターンがある。(1)where句に移動できないケース having句に指定したカラムが,集約関数やvolatile関数だったりする場合。 集約関数などの実行結…

WAL(2)

Recovery バックエンドが異常終了した後、再起動時に実行されるリカバリは,StartupXLOGのdo-whileループで実行される。(コメントにmain redo apply loopとある箇所) ログレコードにページ(ブロック)のバックアップが含まれている場合,RestoreBkpBlocksを実…

WAL(1)

起動後またはチェックポイントが発生した後に、バッファのページを最初に更新する場合,ページ全体をログに出力する。ページのバックアップがないとbackground writerがページを書き込んでいるときにbackendがクラッシュした場合、リカバリが難しくなる。(例…

sum(int4)の高速化

backend/utils/adt/numeric.cのint4_sumで、 Datum int4_sum(PG_FUNCTION_ARGS) { int64 newval; if (PG_ARGISNULL(0)) { /* No non-null input seen so far... */ if (PG_ARGISNULL(1)) PG_RETURN_NULL(); /* still no non-null */ /* This is the first no…

operator

例えば、 select * from branches b where b.bid = 1;というSQLで'='というoperatorがどのように処理されるのか。 parserの処理 make_op()でoper(), make_op_expr()を実行し、executorが使うOpExprデータを作成する。 oper()では、operator名('=')と左辺/右…

lock manager

src/backend/storage/lmgr/READMEより:LOCKING OVERVIEWPostgreSQLは,以下の3種類のロックを使用する。 Spinlocks Spinlockは超短期的なロックを取得することを意図しており,主にLightweight lockのインフラとして使用される。 Spinlockが要求されると,…

Optimizer: exists

現在の実装では、exists句のsubqueryはマージされないため、テーブルのJoin方法はNested loop joinになる。 Nested loop joinでは、Outer側(以下の例ではaccounts)から1行取り出すごとにsubqueryが実行されるため、Outer側のテーブルが大きい場合、検索が非…

Optimizer: in (subquery)の最適化

pull_up_IN_clauses(), convert_IN_to_join()で、in句のsubqueryを上位の階層のqueryにマージしている。 select a.* from accounts a where a.bid in (select bid from branches b where b.bid < 10)このSQLが以下のようになる。 select a.* from accounts a…

Optimizer

PostgreSQLのOptimizerは、Parser/Rewriterで作成されたQuery structureを受け取り、Executorが使うPlan structureを生成する。Optimizerは利用可能な全てのアクセスパスを生成し、最もコストが小さいパスを選択する。 テーブルへのアクセスはTable ScanとIn…

bitmapset

正の整数をbitとして扱うための汎用ルーチン。 bitmapset.h, bitmapset.cで定義されている。bitmapsetでは整数nは、右からn番目のビットが立った2進数へ変換されて扱われる。 例: 0 -> 00000001 1 -> 00000010 2 -> 00000100 3 -> 00001000bitmapセットのデ…

add_path()

optimizer/util/pathnode.cのadd_path()で,pathの候補を追加する。 pathを追加する前に、既に追加されているpathとcompare_fuzzy_path_costs()でコストを比較して、コストが高いpathは削除される(追加されない)。 コストが大体おなじだったときは、pathkey(…

join方法を決めているところ

make_join_rel() -> add_paths_to_joinrel() ここでmerge join, nestloop join, hash joinのpathが作成される。 そしてset_cheapest()でコストが小さいpathが選択される。

improves ExecMakeFunctionResultNoSets

ExecMakeFunctionResultNoSets()などで、FunctionCallInfoData構造体の初期化を高速化するPatch。 FunctionCallInfoData構造体はサイズが大きいので、MemSet()で初期化するよりも、必要最小限のフィールドのみ初期化するほうが効率がいい。