學習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. 小結

今天寫的真輕鬆,因爲要開始學習一個非常龐大的東西了。加油吧自己。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章