BosCollege-SimpleDB-查询执行

Author: Sixing Yan

相关信息
What is BosCollege-SimpleDB? see this.
What is BosCollege-SimpleDB v3.0? see this.

前提提要
这一节将分析Client端发送SQL语句,Server端执行SQL语句的全过程。 我们首先从FindMajors.java入手,探究SimpleDB如何执行一条select查询语句。本文涉及的文件

Step 0

客户端执行一条SQL语句,将该SQL传入Server端并获得结果集,循环访问结果集获取数据记录。
/studentClient/simpledb/FindMajors.java

public class FindMajors {
    public static void main(String[] args) {
        ...
        Connection conn = null;
        try {
            // Step 1: connect to database server
            ...
            // Step 2: execute the query
            Statement stmt = conn.createStatement();
            String qry = "select sname, gradyear "
                       + "from student, dept "
                       + "where did = majorid "
                       + "and dname = '" + major + "'";
            ResultSet rs = stmt.executeQuery(qry);

            // Step 3: loop through the result set
            while (rs.next()) {
                String sname = rs.getString("sname");
                int gradyear = rs.getInt("gradyear");
                System.out.println(sname + "\t" + gradyear);}
            rs.close();
        }...}}

Step 1

stage 1-1

(a) pre-request

Obtain sstmt, an instance of SimpleStatement class
生成一个SimpleStatement类的变量stmt,它实际封装了RemoteStatement类的变量rstmt

  • SimpleStatement(rstmt) <- SimpleConnection.createStatement()
    rstmt <= RemoteStatementImpl(rconn)
    • SimpleConnection封装了RemoteConnectionImpl
    • 实际执行 rstmt:RemoteStatement <- rconn.createStatement()

(b) process

Obtain srs, an instance of SimpleResultSet class
rstmt执行executeQuery(queryString),生成由SimpleResultSet封装的RemoteResultSetImpl类的变量

RemoteStatementImpl.java

  public RemoteResultSet executeQuery(String qry) throws RemoteException {
      try {
         Transaction tx = rconn.getTransaction();
         Plan pln = SimpleDB.planner().createQueryPlan(qry, tx);
         return new RemoteResultSetImpl(pln, rconn);
      }...}
  • SimpleResultSet(rrs)<-rstmt.executeQuery(qry)
  • rrs <= RemoteResultSetImpl(pln,rconn)
    • tx:Transaction <- rconn.getTransaction()
    • pln:Plan <- SimpleDB.planner().createQueryPlan(qry, tx)
    • rrs has 3 members:
      • s:Scan <- pln.open()
      • sch:Schema <- pln.schema()
      • rconn <- rconn

接下来我们看SimpleDB.planner().createQueryPlan(queryString, transaction)完成了哪些工作

stage 1-2

what SimpleDB.planner().createQueryPlan(qry, tx) do?
我们首先看SimpleDB.planner()的工作,它负责初始化server端的planner类实例。
/server/SimpleDB.java

  public static Planner planner() {
      QueryPlanner  qplanner = new BasicQueryPlanner();
      UpdatePlanner uplanner = new BasicUpdatePlanner();
      return new Planner(qplanner, uplanner);
   }

这里实际上是由BasicQueryPlanner类的实例来构造Query plan的工作(如果是create/update等操作则使用BasicUpdatePlanner类)。

  • pln <- qplanner.createQueryPlan(qry, tx)
    • data:QueryData <- Parser(qry).query()
    • qplanner <- BasicQueryPlanner(data, tx)

首先使用Parser类(/parse/Parser.java)来解析SQL语句,形成QueryTree以方便调用。

现在探究“创建Plan”到底做了什么。
/planner/BasicQueryPlanner.java

public class BasicQueryPlanner implements QueryPlanner {
   public Plan createPlan(QueryData data, Transaction tx) {
      //Step 1: Create a plan for each mentioned table or view
      List<Plan> plans = new ArrayList<Plan>();
      for (String tblname : data.tables()) {
         String viewdef = SimpleDB.mdMgr().getViewDef(tblname, tx);
         if (viewdef != null) plans.add(SimpleDB.planner().createQueryPlan(viewdef, tx));
         else plans.add(new TablePlan(tblname, tx)); }
      //Step 2: Create the product of all table plans
      Plan p = plans.remove(0);
      for (Plan nextplan : plans) p = new ProductPlan(p, nextplan);
      //Step 3: Add a selection plan for the predicate
      p = new SelectPlan(p, data.pred());
      //Step 4: Project on the field names
      p = new ProjectPlan(p, data.fields());
      return p;}}

总体来看,createPlan()输入SQL语句的QueryTree(data)以及当前的事务信息(tx),输出一个ProjectPlan类的实例。

首先,递归生成SQL中涉及TablePlan
这一步分别生成SQL中涉及的表的Plan,即是TablePlan

      List<Plan> plans = new ArrayList<Plan>();
      for (String tblname : data.tables()) {
         String viewdef = SimpleDB.mdMgr().getViewDef(tblname, tx);
         if (viewdef != null) plans.add(SimpleDB.planner().createQueryPlan(viewdef, tx));
         else plans.add(new TablePlan(tblname, tx)); }

如果可以查询到tblname相关的视图定义,则递归分析该视图(视图的定义相当于一段select语句),抽取它的最后Plan结果。如果不能查询到相应的视图定义(说明tblname指的是一个table),则为其创建TablePlan类实例。

我们来看TablePlan类是什么,

  • tplist <- ArrayList<TablePlan>
    • tblplan <- TablePlan(tblname, tx), it has two members:
      • ti:TableInfo <- SimpleDB.mdMgr().getTableInfo(tblname, tx)
      • si:StatInfo <- SimpleDB.mdMgr().getStatInfo(tblname, ti, tx)
    • Attention to mdMgr
      • mdMgr:metadataMgr <- SimpleDB.mdMgr()
      • mdMgr has 4 members:
        • tblmgr -> getTableInfo():TableInfo & createTable():void
        • statmgr -> getStatInfo():StatInfo
        • idxmgr -> getIndexInfo():Map<String, IndexInfo>
        • viewmgr -> getViewInfo():String (一条SQL语句,描述View的定义)

接下来看ProductPlan完成的工作。
接着将所有的TablePlan类实例进行Product操作。

  • ProductPlan(p1:TablePlan, p2:TablePlan)初始化,它包含一个schema:Schema 成员
    • Schema类的数据存储结构是HashMap<String,FieldInfo>
      • key 是 fieldname:String, value 是 FieldInfo
      • FieldInfo类有两个 整型 属性,type & length
    • 初始化时,完成schema.addAll(p1.schema()) & schema.addAll(p2.schema())
      • TablePlan用getTableInfo(tblname,tx)生成 TableInfo(tblname, sch, offsets, reclen)
      • TablePlan的schema()返回sch变量
    • schema.addAll(p.schema()) 只是把p的schema的HashMap数据结构和自己的HashMap合并,
    • 所以这里的操作就是把p1和p2的schema合并

第三步是SelectPlan,完成数据的选择
对Product后生成的一个联合大表进行Selection操作。

  • 使用前面生成的Plan类(其实是继承了Plan接口的ProductPlan类)生成SelectPlan类
    • 初始化SelectPlan(p:ProductPlan, data.pred())
    • 这里data:QueryData, data.pred() 返回了一个Predicate类

最后一步是ProjectPlan
记录哪些field需要保留,相当于SQL语句中的“select field1, field2, ...” 部分。


约定用语

a->function() a is the real executor of that function
a<-function() a is generated by that function
a:A a is an instance of class A

类的实例
rstmt RemoteStatement //
rrs RemoteResultSet //
pln Plan //
qry String //
tx Transaction //
ti TableInfo
si StatInfo
sch Schema
s Scan

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343