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中,可是代码很长,因此今天就先不摊开来说了。
留点悬念。
今天写的真轻松,由于要开始学习一个很是庞大的东西了。加油吧本身。