[TOC]
允许用户通过字符界面输入SQL语句实现表的建立/删除;索引的建立/删除以及表记录的插入/删除/查找;
支持三种基本数据类型:INT,CHAR(N),FLOAT,其中CHAR(N)满足 1 <= N <= 255;
一个表最多可以定义32个属性,各属性可以指定是否为UNIQUE;支持单属性的主键定义;
对于表的主属性自动建立B+树索引,对于声明为UNIQUE的属性可以通过SQL语句由用户指定建立/删除B+树索引(因此,所有的B+树索引都是单属性单值的);
可以通过指定用AND连接的多个条件进行查询,支持等值查询和区间查询;
支持每次一条记录的插入操作;支持每次一条或多条记录的删除操作。
设计语言:C++(含有C++17特性并且加入variant库)
环境:Win10, MinGW64
使用项目管理器:Visual Studio
Interpreter模块直接与用户交互,主要实现以下功能:
程序流程控制,即“启动并初始化 à ‘接收命令、处理命令、显示命令结果’循环 $\rightarrow$ 退出”流程。
接收并解释用户输入的命令,生成命令的内部数据结构表示,同时检查命令的语法正确性和语义正确性,对正确的命令调用API层提供的函数执行并显示执行结果,对不正确的命令显示错误信息.
API模块是整个系统的核心,其主要功能为提供执行SQL语句的接口,供Interpreter层调用。该接口以Interpreter层解释生成的命令内部表示为输入,根据Catalog Manager提供的信息确定执行规则,并调用Record Manager、Index Manager和Catalog Manager提供的相应接口进行执行,最后传递执行结果给Interpreter模块。
Catalog Manager负责管理数据库的所有模式信息,包括:
数据库中所有表的定义信息,包括表的名称、表中字段(列)数、主键、定义在该表上的索引。
表中每个字段的定义信息,包括字段类型、是否唯一等。
数据库中所有索引的定义,包括所属表、索引建立在那个字段上等。
Catalog Manager还必需提供访问及操作上述信息的接口,供Interpreter和API模块使用。
Record Manager负责管理记录表中数据的数据文件。主要功能为实现数据文件的创建与删除(由表的定义与删除引起)、记录的插入、删除与查找操作,并对外提供相应的接口。其中记录的查找操作要求能够支持不带条件的查找和带一个条件的查找(包括等值查找、不等值查找和区间查找)。
数据文件由一个或多个数据块组成,块大小应与缓冲区块大小相同。一个块中包含一条至多条记录,为简单起见,只要求支持定长记录的存储,且不要求支持记录的跨块存储。
Index Manager负责B+树索引的实现,实现B+树的创建和删除(由索引的定义与删除引起)、等值查找、插入键值、删除键值等操作,并对外提供相应的接口。
B+树中节点大小应与缓冲区的块大小相同,B+树的叉数由节点大小与索引键大小计算得到。
Buffer Manager负责缓冲区的管理,主要功能有:
根据需要,读取指定的数据到系统缓冲区或将缓冲区中的数据写出到文件
实现缓冲区的替换算法,当缓冲区满时选择合适的页进行替换
记录缓冲区中各页的状态,如是否被修改过等
提供缓冲区页的pin功能,及锁定缓冲区的页,不允许替换出去
为提高磁盘I/O操作的效率,缓冲区与文件系统交互的单位是块,块的大小应为文件系统与磁盘交互单位的整数倍,一般可定为4KB或8KB。
DB Files指构成数据库的所有数据文件,主要由记录数据文件、索引数据文件和Catalog数据文件组成。
typedef boost::variant<int,float,string> value;
class Tuple
{
public:
vector<value>v;
};
enum AttributeType { INT, FLOAT, STRING };
class Attribute
{
public:
string name;
AttributeType type;
int length; //char的长度
bool isUnique;
bool isNULL;
bool isPrimary;
};
class Table
{
public:
string name;
vector<Tuple> tuple; //存放元组
vector<Attribute> attri; //存放属性
vector<Index> index; //存放索引
int attriCnt; //属性数量
int tupleCnt; //元组数量
int indexCnt; //索引数量
};
class Index
{
public:
string name;
string TableName;
string AttriName;
int IndexAddr;
};
主界面由简单的字符界面以及输入提示组成,具体如图所示
读取sql语句
void get_sql(const string& sql);
运行sql语句
int run_sql();
创建表结构文件
int CreateNewTable(const Table* t);
删除表结构文件
int DropTable(const std::string t_name);
创建索引
int CreateNewIndex(const Index* i);
删除索引
int DropIndex(const std::string i_name);
查询表
Table* SelectTable(const std::string t_name);
打印表
void showTable(const Table* t);
创建表
void CreateTable(string table);
删除表
bool DropTable(string table);
插入数据
bool InsertRecord(Table& table, Tuple& tuple);
删除数据
删除单个数据
void DeleteRecord(Table& table, Tuple& tuple);
根据条件删除数据
bool RecordDeleteCondition(const Table& table, vector<Condition>con);
查找数据
vector<Tuple> SelectRecord(const Table& table, const Condition& con);
创建索引
创建索引的参数将由Index Manager的构造函数提供
void createIndex();
删除索引
bool dropIndex();
等值查找
等值查找需要提供相应的键值,返回的是键值在record文件中的偏移地址(int类型)
int searchviakey(const T& key);
范围查找
范围查找需要提供范围,返回的是键值的偏移地址的容器
vector<int> rangesearch(const T& beg, const T& end);
插入新索引值
bool insertkey(const T& key, const int addr);
删除索引值
bool deletekey(const T& key);
初始化索引
当要对一个属性建立索引时,需要给出此属性的所有键值与相应的偏移地址来初始化B+树
void initialize(vector<T> keys, vector<int> records);
将某文件对应的所有块从buffer中清除
void FreeBlock(const string& filename);
根据文件名和偏移量获得块号
int ReadIndexFromFile(const string& filename, int offset);
根据块号,获得块的内容
char* ReadBlockFromFile(int BlockId);
根据块号,将对应的块写回文件
bool writetofile(const int BlockId);
锁定数据块与解锁数据库
void PinBlock(int BlockId);
void UnPinBlock(int BlockId);
将数据库置为已修改
void DirtyBlock(int BlockId);
create table test( a int, b float, c char(10), primary key(a) );
create table test( a int, b float, c char(10), primary key(a) );
insert into test values(1, 2, '12');
insert into test values(1, 2, '12');
insert into test2 values(1, 2, '12');
insert into test values(1, 2);
execfile test.txt;
create table test(
a int,
b float,
c char(10),
primary key(a)
);
insert into test values(1, 2, '12');
insert into test values(2, 3, '13');
insert into test values(3, 4, '15');
insert into test values(2, 5, '13');
select * from test;
select * from test where b<>4;
select * from test where a>=2;
select * from test where a>=2 and a<3;
delete from test where a=3;
insert into test values(3, 8, 'aaaaaa');
insert into test values(2, 3, '13');
create table test(
a int,
b int unique,
c float,
primary key(a)
);
drop table test;
create table test(
a int,
b int unique,
primary key(a)
);
insert into test values (1,2);
insert into test values (2,3);
insert into test values (3,4);
insert into test values (4,5);
insert into test values (5,2);
insert into test values (5,6);
select * from test;
create index bi on test (b);
select * from test where b<=4;
drop index bi;
delete from test where a=3;
delete from tests where a=3;
delete from test where z=3;
select * from student where sage >= 10000 and sage < 10010;
用时0.417s,速度可以接受(含打印时间)
select * from student where sage = 10000;
单值查询用时0.384s(含打印时间)
create index sageIndex on student(sage);
select * from student where sage = 10000;
建立了索引之后查找,仅仅用时0.006s,速度提升50倍
select * from student1 where sage = 10000;
select * from student where sage1 = 10000;
create index sageIndex on student(sage);
在一个拥有20000条记录的属性上建立索引需7.208s,并且已经将B+树全部写入文件,性能良好
create index sage_index on student(sage);
create index sage_index1 on student(sage1);
drop index sage_index;
drop index sage_index;
本程序不同于直接开一个巨大的数组将所有数据进行Hash, Map的方式,本MiniSQL仅使用100个Block大小的缓存(由所有模块共用),所以能够大大减少内存的使用,当执行20000条插入时,全速插入的过程中内存的消耗仅为7.5M
本MiniSQL由于使用的Block数较小,两万行数据的插入+写入文件+建立Primary Key的过程需要2分钟左右,但在后续建立20000条数据的index(B+树),并写入文件仅需7s,并且在index的基础上进行查找仅需要6ms,速度相比没有建立index提升巨大。
总的来说,本次MiniSQL性能达到了我们的预期要求。
Interpreter模块:朱航
API模块:邓承克
Catalog Manager模块:朱航
Record Manager模块:邓承克
Index Manager模块:曾帅
Buffer Manager模块:曾帅
DB Files模块:曾帅,邓承克,朱航
总体设计报告:曾帅,邓承克,朱航
模块汇总:邓承克
联合测试:曾帅、邓承克
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。