• 再读simpledb 之 元数据管理(2)


    前节

    2、(StatMgr)统计信息管理

    统计信息管理器主要维护了一个表的三种统计信息:表文件包含Block的个数,包含记录的条数,以及每个字段非重复记录数。

    image

    图1 统计信息管理

    注:

    StatInfo中,每个字段的非重复记录数是一个经验估计值,大约是1 + (numRecs / 3)。

    如前面所说,统计信息不是持久化到磁盘上,而是在系统启动之初,新建StatMgr对象的时候,自动计算得到。

    private void refreshStatistics(Transaction tx)
    {
        lock (threadLock)
        {
            tablestats = new Dictionary<string, StatInfo>();
            numcalls = 0;
            TableInfo tcatmd = tblMgr.getTableInfo("tblcat", tx);
            RecordFile tcatfile = new RecordFile(tcatmd, tx);
            while (tcatfile.next())
            {
                string tblname = tcatfile.getString("tblname");
                TableInfo md = tblMgr.getTableInfo(tblname, tx);
                StatInfo si = calcTableStats(md, tx);
                tablestats.Add(tblname, si);
            }
            tcatfile.close();
        }
    }

    在计算指定表的统计信息的时候,通过扫描记录文件,获取记录的相关参数,进而统计出整个表的统计信息:

    a. numRecords通过遍历整个表中的记录,计数可得

    b. numBlocks通过扫描最后一条记录的RID中的blockNumber得到。

    :Record的存储

    record类图见前节中的图1。

    上面StatMgr中用到了RecordFile提供的方法,所以这里附上simpledb中表记录的存储细节。

    前面描述了simpledb的存储实现,还记得,在buffer下面,有一个PageFormatter的接口,当初提到说,整个系统只有两个接口实现,其中有一个就是RecordPageFormatter。实际上说,数据库中的表,不是简单地按照顺序的形式写在文件中,而是有其自身的格式限制。表文件有着自己的存储格式,新插入记录按照指定的格式写入到表文件中

    > RecordPageFormatter。

    RecordPageFormatte有一个TableInfo对象,利用这个TableInfo对象包含的表中的字段信息,在表文件被写入真实数据之前,对其进行格式化。

    public void format(Page page)
    {
        int recsize = ti.recordLength() + Page.INT_SIZE;
        for (int pos = 0; pos + recsize <= Page.BLOCK_SIZE; pos += recsize)
        {
            page.setInt(pos, RecordPage.EMPTY);
            makeDefaultRecord(page, pos);
        }
    }

    代码比较简单,通过格式化的方式,可以看出,simpledb是以定长的形式保存记录的。

    makeDefaultRecord方法根据TableInfo提供的schema信息,给字段设置默认值,并将默认值写入文件。

    a. int默认值为0

    b. 字符串默认值为""

    这里要注意下的,是表记录的保存格式:

    是否被使用(IS_USED) 表记录(record)

    IS_USED初始为0,当新添加记录时,会将IS_USED置为1。

    > RecordPage

    联想前存储中提到的Page和Block的对应关系,RecordPage可以看做是一种特殊的Page,管理着对应Block中数据记录的放置和访问。略有不同的是,RecordPage不维护一个contents数组,因为RecordPage只是管理宏观放置和访问,处理的粒度是Record,具体的数据读写,交给Transaction对象来完成。

    RecordPage中主要包含了5个对象:

    blk,当前正在访问的磁盘文件块;

    ti,当前表文件的字段信息;

    tx,当前查询操作所在的事务;

    slotsize,当前Block中,一条记录实际占用的长度;

    currentslot,当前可访问的记录的指针。

    主要从放置和访问(读写插删)两个角度来介绍下RecordPage的功能:

    a. 记录的放置

    我理解就是要插入的新纪录的定位问题:放在那里?

    前面说过,被格式化过的表文件,就如下图所示(还是以studens表为例):

    image

    图2 格式化的空表文件

    image

    图3 插入过数据得到表文件

    关键是一个searchFor(IS_USED)方法,给定参数IS_USED=0时,将currentSlot指针移向可用的位置。

    另外moveToId(id),将currentSlot指针指向指定的位置。

    b. 记录的访问

    首先是定位:记录在整个表中的偏移+字段在记录中的偏移

    然后用tx的对应方法读出数据

    同样先是定位,然后用tx的方法在指定位置写入数据

    首先定位,利用searchFor(0),移动currentSlot到合适的位置

    标记已占用,IS_USED为1,然后交给后面的写方法,写入记录的内容

    使用了标记删除法,不抹去数据,只是将IS_USED标记位设置为0,表示未使用即可。

    > RecordFile

    上面的RecordPage只是负责对一个磁盘数据块的内容的访问,RecordFile则是对整个表记录文件的遍历和访问。

    首先说RecordFile和RecordPage的关系,RecordFile被访问时,不是一次读进来整个文件,而是分成若干个Block,一个BLock一个Block地读,这样在每次访问一个Block的时候,就需要一个RecordPage来访问Block。

    一个RecordFile下面,只维护一个RecordPage对象,指向当前访问的Block。

    另外还维护着一个currentBlocknum,作为一个指针,指向当前访问块的块号。

    RecordFile中包含多个Block,因此,遍历时用到的next()方法:

    首先是检查当前Block是否有next记录

    否则检测是否有下一个可用的Block

    以此类推,直到找到可用的记录,或者到达文件末尾退出。

    public bool next()
    {
        while (true)
        {
            if (rp.next())
                return true;
            if (atLastBlock())
                return false;
            moveTo(currentblknum + 1);
        }
    }

    其他的方法,都是对RecordPage方法的包装,考虑了块的移动造成的影响。

  • 相关阅读:
    perl学习之路3
    perl学习之路1
    年少的忧伤
    莎士比亚的情诗
    自做贪吃蛇游戏的android实现
    伤感的蝴蝶
    爱上下拉列表框Spinner
    相识RadioGroup初恋CheckBox
    EditText和Button的纠缠
    谁陪我一起打包Andriod应用
  • 原文地址:https://www.cnblogs.com/YFYkuner/p/2689745.html
Copyright © 2020-2023  润新知