SQL是一種典型的第四代語言,即4GL,這種語言的突出特色是編寫者不須要關注怎麼作,只須要告訴系統我要什麼就能夠。node
雖然4GL是這樣的一種語言,大大簡化了編寫者的編寫難度,其實底層仍是數據庫的編寫者幫咱們隱藏了具體的實現細節。sql
舉個例子,你媽媽叫你去作一碗西紅柿炒雞蛋,可是並無告訴你如何作,這個時候你查資料,發現了從洗菜到炒菜的全部過程,而後炒了一碗西紅柿炒雞蛋出來。數據庫
對於你的媽媽來講,她很簡單的發出了一個命令,獲得告終果,不過她也不知道具體如何實現的,具體的實現細節被你在廚房掩蓋了。學習
你在廚房關上門來作的事情,其實就是數據庫查詢優化器作的事情,把你的指令分解成具體的執行過程,而後將結果返回給終端客戶。優化
如今來看看查詢優化器的實現。其代碼在optimizer包下面,只有兩個文件:ui
先看看接口實現:spa
package optimizer import ( "planner" ) // Optimizer interface. type Optimizer interface { BuildPlanTree() (*planner.PlanTree, error) }
從這個接口上來看,查詢優化器主要作的事情就是構建一顆查詢計劃樹。接下來開始看看具體的實現過程,首先會看到一個結構體:code
// SimpleOptimizer is a simple optimizer who dispatches the plans type SimpleOptimizer struct { log *xlog.Log database string query string node sqlparser.Statement router *router.Router }
通常來講,執行一個SQL的時候總會遇到這樣一個操做:router
optimizer.NewSimpleOptimizer(log, database, query, node, router).BuildPlanTree()
都會新建一個Optimizer,而後新建一個計劃樹。其實就是新建了一個剛纔的結構體,這是實現的代碼:接口
// NewSimpleOptimizer creates the new simple optimizer. func NewSimpleOptimizer(log *xlog.Log, database string, query string, node sqlparser.Statement, router *router.Router) *SimpleOptimizer { return &SimpleOptimizer{ log: log, database: database, query: query, node: node, router: router, } }
注意這裏的node,這是一個sqlparser.Statement,主要玩的就是這個東西。
好了,接下來就能夠新建查詢計劃樹了:
// BuildPlanTree used to build plan trees for the query. func (so *SimpleOptimizer) BuildPlanTree() (*planner.PlanTree, error) { log := so.log database := so.database query := so.query node := so.node router := so.router plans := planner.NewPlanTree() switch node.(type) { case *sqlparser.DDL: node := planner.NewDDLPlan(log, database, query, node.(*sqlparser.DDL), router) plans.Add(node) case *sqlparser.Insert: node := planner.NewInsertPlan(log, database, query, node.(*sqlparser.Insert), router) plans.Add(node) case *sqlparser.Delete: node := planner.NewDeletePlan(log, database, query, node.(*sqlparser.Delete), router) plans.Add(node) case *sqlparser.Update: node := planner.NewUpdatePlan(log, database, query, node.(*sqlparser.Update), router) plans.Add(node) case *sqlparser.Select: nod := node.(*sqlparser.Select) selectNode := planner.NewSelectPlan(log, database, query, nod, router) plans.Add(selectNode) case *sqlparser.Checksum: node := planner.NewOthersPlan(log, database, query, node, router) plans.Add(node) default: return nil, errors.Errorf("optimizer.unsupported.query.type[%+v]", node) } // Build plantree. if err := plans.Build(); err != nil { return nil, err } return plans, nil }
代碼也不長,就全都貼出來了,其實很簡單,就是對node的類型進行判斷,根據不一樣的類型肯定不一樣的plan。
今天這篇只是引導,因此大體看看就好,先看看其中一個分支的計劃是怎麼建立的:
// NewInsertPlan used to create InsertPlan func NewInsertPlan(log *xlog.Log, database string, query string, node *sqlparser.Insert, router *router.Router) *InsertPlan { return &InsertPlan{ log: log, node: node, router: router, database: database, RawQuery: query, Typ: PlanTypeInsert, Querys: make([]xcontext.QueryTuple, 0, 16), } }
這裏只是返回一個結構體,沒什麼意思,有水平的地方在Build中,可是代碼很長,因此今天就先不攤開來說了。
留點懸念。
今天寫的真輕鬆,由於要開始學習一個很是龐大的東西了。加油吧本身。