B-Treeインデックス。btbeginscan()

インデックスアクセスメソッドのインタフェース定義というものがあり、インデックスの実装を抽象化している。「select * from pg_am」とすれば、インデックスの種類ごとのインタフェースを実装した関数の名前がわかる。
B-Treeインデックスの場合、次のもの。

  • btinsert
  • btbeginscan
  • btgettuple
  • btgetmulti
  • btrescan
  • btendscan
  • btmarkpos
  • btrestrpos
  • btbuild
  • btbulkdelete
  • btvacuumcleanup
  • btcostestimate

これらを中心に見れば、B-Treeインデックスがやっていることがわかるはず。この前は、btgettuple()あたりを見た。今回は、名前からしてインデックススキャンが始まるときに呼ばれるbtbeginscan()を見てみる。

GDBを使ってしらべた呼び出しシーケンス(抜粋)。

(gdb) bt
#0  btrescan (fcinfo=0xbfb657e0) at nbtree.c:363
#1  0x0831df38 in FunctionCall2 (flinfo=0x84e1d30, arg1=139420248, arg2=139420120) at fmgr.c:1279
#2  0x080a840e in index_rescan (scan=0x84f6258, key=0x84f61d8) at indexam.c:321
#3  0x080a7e5e in RelationGetIndexScan (indexRelation=0xb5600938, nkeys=1, key=0x84f61d8) at genam.c:106
#4  0x080aeef8 in btbeginscan (fcinfo=0xbfb65a90) at nbtree.c:352
#5  0x0831dff8 in FunctionCall3 (flinfo=0x84e1ce8, arg1=3042969912, arg2=1, arg3=139420120) at fmgr.c:1304
#6  0x080a830e in index_beginscan_internal (indexRelation=0xb5600938, nkeys=1, key=0x84f61d8) at indexam.c:281
#7  0x080a8208 in index_beginscan (heapRelation=0xb55fee28, indexRelation=0xb5600938, snapshot=0x84e2d18, nkeys=1, key=0x84f61d8) at indexam.c:222
#8  0x081a1adb in ExecInitIndexScan (node=0x84f3fd8, estate=0x84f5748, eflags=0) at nodeIndexscan.c:592
#9  0x0818f077 in ExecInitNode (node=0x84f3fd8, estate=0x84f5748, eflags=0) at execProcnode.c:169
#10 0x0818c11a in InitPlan (queryDesc=0x84e2d40, eflags=0) at execMain.c:666
#11 0x0818b890 in ExecutorStart (queryDesc=0x84e2d40, eflags=0) at execMain.c:200
#12 0x0824e4b7 in PortalStart (portal=0x84d9cb0, params=0x0, snapshot=0x0) at pquery.c:528
#13 0x082492e2 in exec_simple_query (query_string=0x84ac870 select * from accounts where aid = 100) at postgres.c:949

btbeginscan()は、最終的にbtrescan()を呼び出しているので、btrescan()までのシーケンスを確認。btrescan()は単独でも呼ばれる。単独で呼ばれるのはドキュメントを見る限りだとネステッドループ結合のときのよう。


主な関数は以下のとおり。indexam.cの関数はインデックス実装の関数に対するファサードのようなものなので以下には含めていない。

  • btrescan()
    • IndexScanDescから参照されるBTScanOpaqueを初期化する。BTScanOpaqueはインデックスアクセスメソッドのプライベートな情報を格納する(どこまでヒットしたとか)。killedItemsとかmarkPosとかのメンバの役割がよくわからない。
  • RelationGetIndexScan()
    • IndexScanDescを作成する。IndexScanDescは、ヒープのリレーションやインデックスのリレーション情報、スナップショット、インデックスに対応するヒープのタプルに関する情報などをもつ。
  • btbeginscan()
    • IndexScanDescを返す。
  • ExecInitIndexScan()
    • IndexScanStateを作成する。IndexScanStateはPlanStateのサブタイプ相当。実行計画のノードIndexScanに対応する実行時のノード。インデックススキャン実行時の状態を管理する構造体。クエリの実行全体の状態は、EStateという構造体で管理し、実行を表す木構造の各ノードでは、それに対応する構造体(ここではIndexScanState)で管理するというしくみになっているように見える。
    • ヒープのリレーションやインデックスのリレーションをオープン。
    • ExecIndexBuildScanKeys()を呼び出しScanKeyを作成する。
      • 実行計画の情報を見て、定数との比較なのか、定数以外との比較なのか、列との比較なのか、配列との比較なのか、NULLとの比較なのかが考慮される。