クエリのパース処理

これからしばらくSQLのパースから実行までを見ていこうかなと思う。結合、サブクエリ、集約等がどう処理されるか理解したい。それと集合論的な考え方を身につけたいなぁ。

とりあえずはNested Loop Join が行われるSQLで考える。パースツリー、クエリツリー、プランツリーのノードをデバッグ用の関数pprint()で出力してみた。パースツリー、クエリツリー、プランツリーの用語はhttp://www2b.biglobe.ne.jp/~caco/webdb-pdfs/vol27.pdfを参考にした。

どんなノード(のデータ構造)があるのか把握するところから始めようなかな。

SQL

pgbenchでつくったテーブルをつかっている。

select * from accounts a inner join branches b on a.bid = b.bid where a.aid = 100
実行計画

explainした結果。ちゃんとNested Loop Joinになっている。

 Nested Loop  (cost=0.00..9.58 rows=1 width=461)
   Join Filter: (a.bid = b.bid)
   ->  Index Scan using accounts_pkey1 on accounts a  (cost=0.00..8.36 rows=1 width=97)
         Index Cond: (aid = 100)
   ->  Seq Scan on branches b  (cost=0.00..1.10 rows=10 width=364)
生のパースツリー

pg_parse_query()の後でgdbで止めてpprint()した。

   {SELECT
   :distinctClause <>
   :intoClause <>
   :targetList (
      {RESTARGET
      :name <>
      :indirection <>
      :val
         {COLUMNREF
         :fields ("*")
         :location 7
         }
      :location 7
      }
   )
   :fromClause (
      {JOINEXPR
      :jointype 0
      :isNatural false

      :larg
         {RANGEVAR
         :schemaname <>
         :relname accounts
         :inhOpt 2
         :istemp false
         :alias
            {ALIAS
            :aliasname a
            :colnames <>
            }
         }
      :rarg
         {RANGEVAR
         :schemaname <>
         :relname branches
         :inhOpt 2
         :istemp false
         :alias
            {ALIAS
            :aliasname b
            :colnames <>
            }
         }
      :using <>
      :quals
         {AEXPR
         :name ("=")
         :lexpr
            {COLUMNREF
            :fields ("a" "bid")
            :location 50
            }
         :rexpr
            {COLUMNREF
            :fields ("b" "bid")
            :location 58
            }
         :location 56
         }
      :alias <>
      :rtindex 0
      }
   )
   :whereClause
      {AEXPR
      :name ("=")
      :lexpr
         {COLUMNREF
         :fields ("a" "aid")
         :location 70
         }
      :rexpr
         {A_CONST
         :val 100
         :typename <>
         }
      :location 76
      }
   :groupClause <>
   :havingClause <>
   :valuesLists <>
   :sortClause <>
   :limitOffset <>
   :limitCount <>
   :lockingClause <>
   :op 0
   :all false
   :larg <>
   :rarg <>
   }

リライト後のクエリツリー

pg_analyze_and_rewrite()の後でgdbで止めてpprint()した。長い。

   {QUERY
   :commandType 1
   :querySource 0
   :canSetTag true
   :utilityStmt <>
   :resultRelation 0
   :intoClause <>
   :hasAggs false
   :hasSubLinks false
   :rtable (
      {RTE
      :alias
         {ALIAS
         :aliasname a
         :colnames <>
         }
      :eref
         {ALIAS
         :aliasname a
         :colnames ("aid" "bid" "abalance" "filler")
         }
      :rtekind 0
      :relid 16453
      :inh true
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      }
      {RTE
      :alias
         {ALIAS
         :aliasname b
         :colnames <>
         }
      :eref
         {ALIAS
         :aliasname b
         :colnames ("bid" "bbalance" "filler")
         }
      :rtekind 0
      :relid 16447
      :inh true
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      }
      {RTE
      :alias <>
      :eref
         {ALIAS
         :aliasname unnamed_join
         :colnames ("aid" "bid" "abalance" "filler" "bid" "bbalance" "filler")
         }
      :rtekind 2
      :jointype 0
      :joinaliasvars (
         {VAR
         :varno 1
         :varattno 1
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 1
         :varoattno 1
         }
         {VAR
         :varno 1
         :varattno 2
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 1
         :varoattno 2
         }
         {VAR
         :varno 1
         :varattno 3
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 1
         :varoattno 3
         }
         {VAR
         :varno 1
         :varattno 4
         :vartype 1042
         :vartypmod 88
         :varlevelsup 0
         :varnoold 1
         :varoattno 4
         }
         {VAR
         :varno 2
         :varattno 1
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 2
         :varoattno 1
         }
         {VAR
         :varno 2
         :varattno 2
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 2
         :varoattno 2
         }
         {VAR
         :varno 2
         :varattno 3
         :vartype 1042
         :vartypmod 92
         :varlevelsup 0
         :varnoold 2
         :varoattno 3
         }
      )
      :inh false
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      }
   :jointree
      {FROMEXPR
      :fromlist (
         {JOINEXPR
         :jointype 0
         :isNatural false
         :larg
            {RANGETBLREF
            :rtindex 1
            }
         :rarg
            {RANGETBLREF
            :rtindex 2
            }
         :using <>
         :quals
            {OPEXPR
            :opno 96
            :opfuncid 65
            :opresulttype 16
            :opretset false
            :args (
               {VAR
               :varno 1
               :varattno 2
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 1
               :varoattno 2
               }
               {VAR
               :varno 2
               :varattno 1
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 2
               :varoattno 1
               }
            )
            }
         :alias <>
         :rtindex 3
         }
      )
      :quals
         {OPEXPR
         :opno 96
         :opfuncid 65
         :opresulttype 16
         :opretset false
         :args (
            {VAR
            :varno 1
            :varattno 1
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 1
            :varoattno 1
            }
            {CONST
            :consttype 23
            :consttypmod -1
            :constlen 4
            :constbyval true
            :constisnull false
            :constvalue 4 [ 100 0 0 0 ]
            }
         )
         }
      }
   :targetList (
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 1
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 3
         :varoattno 1
         }
      :resno 1
      :resname aid
      :ressortgroupref 0
      :resorigtbl 16453
      :resorigcol 1
      :resjunk false
      }
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 2
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 3
         :varoattno 2
         }
      :resno 2
      :resname bid
      :ressortgroupref 0
      :resorigtbl 16453
      :resorigcol 2
      :resjunk false
      }
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 3
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 3
         :varoattno 3
         }
      :resno 3
      :resname abalance
      :ressortgroupref 0
      :resorigtbl 16453
      :resorigcol 3
      :resjunk false
      }
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 4
         :vartype 1042
         :vartypmod 88
         :varlevelsup 0
         :varnoold 3
         :varoattno 4
         }
      :resno 4
      :resname filler
      :ressortgroupref 0
      :resorigtbl 16453
      :resorigcol 4
      :resjunk false
      }
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 5
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 3
         :varoattno 5
         }
      :resno 5
      :resname bid
      :ressortgroupref 0
      :resorigtbl 16447
      :resorigcol 1
      :resjunk false
      }
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 6
         :vartype 23
         :vartypmod -1
         :varlevelsup 0
         :varnoold 3
         :varoattno 6
         }
      :resno 6
      :resname bbalance
      :ressortgroupref 0
      :resorigtbl 16447
      :resorigcol 2
      :resjunk false
      }
      {TARGETENTRY
      :expr
         {VAR
         :varno 3
         :varattno 7
         :vartype 1042
         :vartypmod 92
         :varlevelsup 0
         :varnoold 3
         :varoattno 7
         }
      :resno 7
      :resname filler
      :ressortgroupref 0
      :resorigtbl 16447
      :resorigcol 3
      :resjunk false
      }
   )
   :returningList <>
   :groupClause <>
   :havingQual <>
   :distinctClause <>
   :sortClause <>
   :limitOffset <>
   :limitCount <>
   :rowMarks <>
   :setOperations <>
   }
プランツリー

pg_plan_queries()が終わった後でgdbで止めてpprint()した。これも長いよ。

   {PLANNEDSTMT
   :commandType 1
   :canSetTag true
   :planTree
      {NESTLOOP
      :startup_cost 0.00
      :total_cost 9.58
      :plan_rows 1
      :plan_width 461
      :targetlist (
         {TARGETENTRY
         :expr
            {VAR
            :varno 65001
            :varattno 1
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 1
            :varoattno 1
            }
         :resno 1
         :resname aid
         :ressortgroupref 0
         :resorigtbl 16453
         :resorigcol 1
         :resjunk false
         }
         {TARGETENTRY
         :expr
            {VAR
            :varno 65001
            :varattno 2
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 1
            :varoattno 2
            }
         :resno 2
         :resname bid
         :ressortgroupref 0
         :resorigtbl 16453
         :resorigcol 2
         :resjunk false
         }
         {TARGETENTRY
         :expr
            {VAR
            :varno 65001
            :varattno 3
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 1
            :varoattno 3
            }
         :resno 3
         :resname abalance
         :ressortgroupref 0
         :resorigtbl 16453
         :resorigcol 3
         :resjunk false
         }
         {TARGETENTRY
         :expr
            {VAR
            :varno 65001
            :varattno 4
            :vartype 1042
            :vartypmod 88
            :varlevelsup 0
            :varnoold 1
            :varoattno 4
            }
         :resno 4
         :resname filler
         :ressortgroupref 0
         :resorigtbl 16453
         :resorigcol 4
         :resjunk false
         }
         {TARGETENTRY
         :expr
            {VAR
            :varno 65000
            :varattno 1
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 2
            :varoattno 1
            }
         :resno 5
         :resname bid
         :ressortgroupref 0
         :resorigtbl 16447
         :resorigcol 1
         :resjunk false
         }
         {TARGETENTRY
         :expr
            {VAR
            :varno 65000
            :varattno 2
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 2
            :varoattno 2
            }
         :resno 6
         :resname bbalance
         :ressortgroupref 0
         :resorigtbl 16447
         :resorigcol 2
         :resjunk false
         }
         {TARGETENTRY
         :expr
            {VAR
            :varno 65000
            :varattno 3
            :vartype 1042
            :vartypmod 92
            :varlevelsup 0
            :varnoold 2
            :varoattno 3
            }
         :resno 7
         :resname filler
         :ressortgroupref 0
         :resorigtbl 16447
         :resorigcol 3
         :resjunk false
         }
      )
      :qual <>
      :lefttree
         {INDEXSCAN
         :startup_cost 0.00
         :total_cost 8.36
         :plan_rows 1
         :plan_width 97
         :targetlist (
            {TARGETENTRY
            :expr
               {VAR
               :varno 1
               :varattno 1
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 1
               :varoattno 1
               }
            :resno 1
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
            {TARGETENTRY
            :expr
               {VAR
               :varno 1
               :varattno 2
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 1
               :varoattno 2
               }
            :resno 2
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
            {TARGETENTRY
            :expr
               {VAR
               :varno 1
               :varattno 3
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 1
               :varoattno 3
               }
            :resno 3
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
            {TARGETENTRY
            :expr
               {VAR
               :varno 1
               :varattno 4
               :vartype 1042
               :vartypmod 88
               :varlevelsup 0
               :varnoold 1
               :varoattno 4
               }
            :resno 4
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
         )
         :qual <>
         :lefttree <>
         :righttree <>
         :initPlan <>
         :extParam (b)
         :allParam (b)
         :scanrelid 1
         :indexid 16464
         :indexqual (
            {OPEXPR
            :opno 96
            :opfuncid 65
            :opresulttype 16
            :opretset false
            :args (
               {VAR
               :varno 1
               :varattno 1
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 1
               :varoattno 1
               }
               {CONST
               :consttype 23
               :consttypmod -1
               :constlen 4
               :constbyval true
               :constisnull false
               :constvalue 4 [ 100 0 0 0 ]
               }
            )
            }
         )
         :indexqualorig (
            {OPEXPR
            :opno 96
            :opfuncid 65
            :opresulttype 16
            :opretset false
            :args (
               {VAR
               :varno 1
               :varattno 1
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 1
               :varoattno 1
               }
               {CONST
               :consttype 23
               :consttypmod -1
               :constlen 4
               :constbyval true
               :constisnull false
               :constvalue 4 [ 100 0 0 0 ]
               }
            )
            }
         )
         :indexstrategy (i 3)
         :indexsubtype (o 23)
         :indexorderdir 1
         }
      :righttree
         {SEQSCAN
         :startup_cost 0.00
         :total_cost 1.10
         :plan_rows 10
         :plan_width 364
         :targetlist (
            {TARGETENTRY
            :expr
               {VAR
               :varno 2
               :varattno 1
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 2
               :varoattno 1
               }
            :resno 1
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
            {TARGETENTRY
            :expr
               {VAR
               :varno 2
               :varattno 2
               :vartype 23
               :vartypmod -1
               :varlevelsup 0
               :varnoold 2
               :varoattno 2
               }
            :resno 2
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
            {TARGETENTRY
            :expr
               {VAR
               :varno 2
               :varattno 3
               :vartype 1042
               :vartypmod 92
               :varlevelsup 0
               :varnoold 2
               :varoattno 3
               }
            :resno 3
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
         )
         :qual <>
         :lefttree <>
         :righttree <>
         :initPlan <>
         :extParam (b)
         :allParam (b)
         :scanrelid 2
         }
      :initPlan <>
      :extParam (b)
      :allParam (b)
      :jointype 0
      :joinqual (
         {OPEXPR
         :opno 96
         :opfuncid 65
         :opresulttype 16
         :opretset false
         :args (
            {VAR
            :varno 65001
            :varattno 2
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 1
            :varoattno 2
            }
            {VAR
            :varno 65000
            :varattno 1
            :vartype 23
            :vartypmod -1
            :varlevelsup 0
            :varnoold 2
            :varoattno 1
            }
         )
         }
      )
      }
   :rtable (
      {RTE
      :alias
         {ALIAS
         :aliasname a
         :colnames <>
         }
      :eref
         {ALIAS
         :aliasname a
         :colnames ("aid" "bid" "abalance" "filler")
         }
      :rtekind 0
      :relid 16453
      :inh false
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      }
      {RTE
      :alias
         {ALIAS
         :aliasname b
         :colnames <>
         }
      :eref
         {ALIAS
         :aliasname b
         :colnames ("bid" "bbalance" "filler")
         }
      :rtekind 0
      :relid 16447
      :inh false
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      }
      {RTE
      :alias <>
      :eref
         {ALIAS
         :aliasname unnamed_join
         :colnames ("aid" "bid" "abalance" "filler" "bid" "bbalance" "filler")
         }
      :rtekind 2
      :jointype 0
      :joinaliasvars <>
      :inh false
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      }
   )
   :resultRelations <>
   :utilityStmt <>
   :intoClause <>
   :subplans <>
   :rewindPlanIDs (b)
   :returningLists <>
   :rowMarks <>
   :relationOids (o 16453 16447)
   :nParamExec 0
   }