• 学习RadonDB源码(三)


    1. 所谓第四代语言

    SQL是一种典型的第四代语言,即4GL,这种语言的突出特点是编写者不需要关注怎么做,只需要告诉系统我要什么就可以。

    虽然4GL是这样的一种语言,大大简化了编写者的编写难度,其实底层还是数据库的编写者帮我们隐藏了具体的实现细节。

    举个例子,你妈妈叫你去做一碗西红柿炒鸡蛋,但是并没有告诉你如何做,这个时候你查资料,发现了从洗菜到炒菜的所有过程,然后炒了一碗西红柿炒鸡蛋出来。

    对于你的妈妈来说,她很简单的发出了一个命令,得到了结果,不过她也不知道具体如何实现的,具体的实现细节被你在厨房掩盖了。

    2. RadonDB的查询优化器

    你在厨房关上门来做的事情,其实就是数据库查询优化器做的事情,把你的指令分解成具体的执行过程,然后将结果返回给终端客户。

    现在来看看查询优化器的实现。其代码在optimizer包下面,只有两个文件:

    • optimizer.go 这个文件声明了一个接口
    • simple_optimizer.go 这个文件则是具体的实现。

    先看看接口实现:

    package optimizer
    
    import (
    	"planner"
    )
    
    // Optimizer interface.
    type Optimizer interface {
    	BuildPlanTree() (*planner.PlanTree, error)
    }
    

    从这个接口上来看,查询优化器主要做的事情就是构建一颗查询计划树。接下来开始看看具体的实现过程,首先会看到一个结构体:

    // 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的时候总会遇到这样一个操作:

    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中,但是代码很长,所以今天就先不摊开来讲了。

    留点悬念。

    3. 小结

    今天写的真轻松,因为要开始学习一个非常庞大的东西了。加油吧自己。

  • 相关阅读:
    [转载]Matlab实用小技巧
    Matlab rand randn randint
    Matlab取整
    Mathtype报错:MathType has detected an error in....
    [转载]十大编程算法助程序员走上高手之路
    (转)Free函数的参数一定要是malloc返回的那个指针
    sizeof,一个其貌不扬的家伙(转)
    ISO C Random Number Functions
    srand() rand() time(0)
    IOS之文件夹创建、删除,图片在本地的保存和加载
  • 原文地址:https://www.cnblogs.com/wingsless/p/10896525.html
Copyright © 2020-2023  润新知