INFR11199-高级数据库系统(2024年春季)课程课业
到期时间:2024年3月28日星期四中午12:00重要:
抄袭:每个学生都必须单独完成本项目课业。
此项目的所有代码都必须是您自己的。您不能复制源代码来自其他学生或你在网上找到的其他来源。你不能分享
你和其他学生的代码。您不能将代码托管在公共代码上
存储库。
每次提交都将使用剽窃检测软件进行检查。
剽窃行为将向学校和学院学术不端官员报告。
有关更多信息,请参阅大学关于学术不端行为的页面。
尽早开始,循序渐进。之前请仔细阅读课业说明
你开始编程。
该课业总分为100分,占你最终成绩的40%。
1.
INFR11199(2024春季)课业第2页,共17页1目标和要点
在本项目任务中,您将实现一个轻量级数据库管理系统
称为LightDB。这项任务的目标有三个:
教您如何将SQL查询转换为关系代数查询计划,
熟悉用于关系运算符评估的迭代器模型,以及
构建最常见运算符的简单实现(例如,选择、投影、联接、排序、聚合)。任务包括两项任务:
任务1(60%):迭代器模型和常见运算符的实现。
任务2(30%):优化已构建的查询计划。
剩下的10%的分数用于代码样式和注释;稍后会有更多详细信息。任务2需要独立思考和创造力,这对于
根据通用标记方案进行区分标记。
您将从一个仅由主要类组成的基本项目开始
LightDB,它定义了预期的命令行接口。您可以自由修改这个类,但必须保留命令行接口。项目也已配置
使用JSqlParser1
,所以您不必编写自己的SQL解析器(除非您愿意
到main类提供了一个如何将SQL字符串解析为Java对象的示例。本文档的其余部分详细描述了如何完成任务。拿
是时候仔细阅读了。请注意,本课程稍后将介绍一些主题。开始尽早工作。这不是一个应该拖到最后一分钟的项目。
您可以从复习有关SQL的课程材料开始。此外,复习一下面向对象编程的基本原理(封装、继承、,多态性、抽象)和设计模式;特别是singleton模式和访问者模式可能会在这项任务中派上用场。
1.https://github.com/JSQLParser/JSqlParser课程课业继续。
INFR11199(2024春季)课业第3页,共17页2概述
在这个项目中,您将实现一个简单的SQL语句解释器。也就是说,你将构建一个程序,该程序接收一个数据库(一组包含数据的文件)和一个输入文件包含一个SQL查询。该程序将处理和评估上的SQL查询数据库,并将查询结果写入指定的输出文件中。
2.1支持的语言功能
您的解释器将不支持所有的SQL,但它将处理许多相对复杂的查询。在这里,我们提供有关您必须支持的查询的信息。您的解释器将处理SELECT-FROM-WERE查询,这些查询可以选择在SELECT中包括SUM聚合、DISTINCT、ORDER BY、GROUP BY或它们的组合。您不需要支持嵌套的子查询、设置运算符(例如。,UNION)、除SUM之外的聚合函数(例如,COUNT、AVG)或任何其他功能。在里面此外,我们做了一些简化的假设,如下所示。当我们说查询有效时,我们的意思是,这是对您的口译员的允许输入,您应该能够处理。当我们谈论基表时,我们指的是数据库中存在的真实表。您可以假设所有有效的查询都遵循正确的SQL语法,并且它们只引用到数据库中存在的表。此外,当查询引用表列时
例如Sailors.age,您可以假设列名(年龄)对此有效表(水手)。
您可以假设FROM子句中至少有一个表。
有效查询可能使用别名,如Sailors S,也可能仅使用的名称基本表。如果查询不使用别名,则所有列引用都是完全限定的按基表名称。如果查询确实使用别名,则所有表都使用别名列引用由别名限定。这里有两个有效查询的例子,
第一个没有别名,第二个有别名:
从水手处选择水手姓名,预订日期,预订
其中Sailors.id=Reserves.id;选择S.name,R.date FROM Sailors S,Reservations R其中S.id=R.sid;
您可以假设任何用作别名的字符串都不是
基本表。
自联接,即将表与自身联接,是有效的,必须得到支持(以及需要使用别名)。
课程课业继续。
INFR11199(2024春季)课业第4页,共17页WHERE子句(如果存在)是
形式A op B,其中op是=,!=,<,>,<=,>=之一A和B是整数或列引用。因此,Sailors.id=储量.sid,S.id<3和42=42都是WHERE原因的有效表达式,而例如Sailors.id<Boats.id-1不是一个有效的表达式,即使它可以在“真正的SQL”中。
SELECT子句将指定列的子集或具有SELECT形式. 在这两种情况下,它都可以选择性地包括SUM聚合函数。对于SELECT,您应该按照表格的顺序对答案中的列进行排序
在FROM子句中。因此,对于SELECTFROM R,S,每个应答行都具有R的列后面跟着S的所有列。表中列的顺序为
由表架构定义。
SELECT子句可以选择性地包含一个SUM聚合函数。我们限制将一项(整数或列)作为参数的SUM函数的形式
参考)或术语的乘积。因此为了这个赋值的目的SUM(5),SUM(A)、SUM(AB)和SUM(CCC)是有效的表达式,而例如SUM(A+B)和SUM(A/2)不是有效的表达式。
您可以假设SUM(如果存在)始终位于SELECT子句的末尾。它是SELECT可能仅由一个SUM组成;例如,SELECT SUM(1)FROM R有效并返回一个整数,表示R中元组的数量。
可能存在GROUP BY子句,该子句指定了用于分组的列的子集。SELECT列表只能按列列出组,但不一定全部列出,即即,某些逐列分组可以从输出中省略;例如,从中选择
R GROUP BY A,B是一个有效的查询。您可能会认为HAVING不会被使用。SUM函数(如果存在)可以引用任何列,包括非分组依据柱;例如,SELECT A,SUM(AB)FROM R GROUP BY A是有效的查询。可能有一个ORDER BY子句,用于指定列的子集进行排序。您可以假设我们只想按升序排序。如果两个元组一致
对于所有排序属性,您可以根据自己的喜好对它们进行排序。你可能会认为没有将使用ASC、DESC、OFFSET或LIMIT关键字。您还可以假设ORDER BY中提到的属性是的子集
SELECT保留的那些。这允许您在投影之后最后进行排序。请注意,这并不意味着必须提及ORDER BY中的每个属性在SELECT中–像SELECTFROM Sailors S ORDER BY S.name这样的查询是有效的。SELECT之后可能会出现DISTINCT,应进行适当处理。是的,从中选择DISTINCT*。。。是有效的。课程课业继续。
INFR11199(2024春季)课业第5页,共17页2.2数据和输出格式
我们已经为您提供了一些示例数据和一些示例查询。看看samples目录。它将数据库、输入和预期输出作为子目录。输入目录包含带有一些示例查询的SQL文件。有一个
每个输入文件的SQL查询。
db目录包含schema.txt,将数据库的架构指定代 写INFR11199-高级数据库系统为以及存储数据本身的数据目录。名称schema.txt并且数据是硬编码的,并且必须存在于有效的数据库目录中。您的程序应该支持schema.txt中定义的任意模式,而不仅仅是的模式样本数据。
schema.txt文件包含数据库中每个关系(表)的一行。每一个行包含几个用空格分隔的字符串。每行上的第一个字符串是表名,其余的都是属性(列)名,按顺序排列
它们出现在表格中。
数据子目录包含每个数据库表一个文件和文件名
与添加了.csv扩展名的数据库表的名称相同。每一个文件包含零个或多个元组;元组是文件中带有字段(attribute)的一行用逗号分隔的值。所有属性值都是整数。使用integer属性可以简化您的工作,并使您能够专注于实现“有趣的”功能而不是样板代码来处理不同的数据类型。还有,你
不必处理null值,但您确实需要处理空表。
预期输出目录包含查询的预期输出文件
我们提供了。例如,query1.csv包含查询的预期输出在query1.sql中。输出的格式与格式相同
2.4编译和运行
SQL解释器是一个接受三个参数的程序:数据库的路径目录、输入SQL文件的路径和输出文件的路径。然后程序课程课业继续。
INFR11199(2024春季)课业第6页,共17页从给定数据库上的输入文件执行SQL查询,并将结果写入给定的输出文件。LightDB.java文件提供了这个命令行界面。跑从IDE或命令行中的LightDB类,提供所需的参数。我们将从命令行编译您的代码,生成一个可运行的.jar文件:mvn干净编译程序集:单个
此命令将生成target/lightdb-1.0.0-jar-with-dependences.jar。我们可以按如下方式运行此文件:
$java-jar target/lightdb-1.0.0-jar-with-dependences.jar用法:LightDB database_dir input_file output_fileLightDB类需要传递三个强制参数。
$java-jar target/lightdb-1.0.0-jar-with-dependences.jarsamples/db samples/input/query1.sql samples/output/query1.csv阅读声明:SELECTFROM Sailors
选择主体是SelectFROM Sailors
您的代码应该适当地处理这些参数(即,不要硬编码任何路径)。我们将使用我们自己的测试查询和数据库来测试您的代码不同的模式,包括不同的表名。数据库目录将具有
与上述结构相同,数据目录中的文件根据
以.csv作为文件扩展名的数据库架构。您可以假设在执行给定的输出文件不存在,但输出目录确实存在。
在我们运行您的代码后,我们将比较您的输出文件和我们的输出文件。对于查询如果没有ORDER BY,如果您的应答文件中的应答元组的顺序不同,也可以到我们的;对于ORDER BY查询,您的排序必须与我们的排序相匹配属性,而绑定元组可能与我们的顺序不同。正如你所能想象的对于您来说,尊重预期的输入和输出格式是非常重要的。注意:我们将在使用Ubuntu Linux的DICE机器上测试您的代码。回想起Linux/MacOS环境使用“/”作为路径分隔符。数据库目录将如上所述,不提供最终的“/”符号。如果您使用Windows,请确保如果要形成文件路径,请使用file.separator而不是“\”作为路径分隔符。2.5算子与迭代模型
这个项目中的一个关键抽象将是关系运算符的迭代器模型。你将实现几个运算符:
bag关系代数选择、投影和(元组嵌套循环)连接。
课程课业继续。
INFR11199(2024春季)课业第7页,共17页排序、重复消除和按聚合运算符分组,这些运算符不是一部分但必须添加以支持ORDER BY、DISTINCT、,GROUP BY和SUM。
扫描运算符,它是任何查询计划的叶运算符。这真的是一个物理运算符,而不是添加到关系代数中的东西,
但现在我们将把它归入与上述相同的类别。
实现所有关系运算符的标准方法是使用迭代器API。
您应该创建一个抽象类Operator,所有的运算符都会扩展它。某些运算符可能有一个或两个子运算符。扫描操作员没有子女,联接有两个子级,其余操作符有一个子级。您的最终目标是构建一个作为运算符树的查询计划。
每个运算符都必须实现getNextTuple()和reset()方法(put这些在您的抽象运算符类中)。这个想法是,一旦你创建了一个关系运算符,可以重复调用getNextTuple()来获取该运算符的下一个元组输出这有时被称为运算符中的“拉元组”。如果操作员仍然如果有一些可用的输出,它将返回下一个元组,否则应返回null。reset()方法告诉运算符重置其状态并开始返回其输出再次从头开始;也就是说,在对运算符调用reset()之后,将进行后续调用getNextTuple()返回该运算符输出中的第一个元组,即使元组以前可能已返回。如果您需要处理,此功能非常有用运算符的输出多次,例如,在联接中重复扫描内部表。
对于上面的每个运算符,您将同时实现getNextTuple()和reset()。请记住,如果您的运算符有一个子运算符,则getNextTuple()的运算符可以并且可能会调用子运算符上的getNextTuple(),并且对它从子级接收到的输出执行一些有用的操作。
迭代器模型的一大优势,也是它流行的原因之一,是它
支持多操作员计划的流水线评估,即在不将中间结果具体化(写入磁盘)的情况下进行评估。该项目的大部分涉及实施上述运营商中的每一个,
以及编写代码以将SQL查询(即一行文本)翻译成查询计划(即。,合适的算子树)。一旦您有了查询计划,您就可以实际计算通过在根运算符上重复调用getNextTuple()来获得查询的答案,以及把元组放在某个地方。
我们建议您在抽象运算符类中添加一个dump()方法。这种方法重复调用getNextTuple(),直到下一个元组为null(不再输出)并写入每个元组到合适的PrintStream。这样你就可以转储()任何运算符(包括查询计划的根)到您喜爱的PrintStream,无论它会导致一个文件,或者它是否为System.out(用于测试)。课程课业继续。
INFR11199(2024春季)课业第8页,共17页3任务1:迭代器模型实现
我们建议您一次实现和测试一个功能。我们的说明
以下是建议的实施顺序。
我们还建议(但不要求)您尽早设置测试基础设施。
您应该进行两种测试——针对单个组件的单元测试和端到端测试测试在查询中运行解释器的位置,并查看生成的输出文件看看它们是否与一组预期的输出文件匹配。添加更多功能时,请重新运行所有测试,以检查是否没有引入影响早期功能的错误。
在实现和测试每个功能后,制作代码的副本并保存,以便在如果你以后搞砸了,你仍然有一个有效的版本(并且你可以提交部分版本如果其他一切都失败了,那就值得称赞!)。
3.1设置JSqlParser
对于这个项目,您不需要编写自己的SQL解析器。我们建议使用JSqlParser,它负责解析SQL并创建Java对象。JSqlParser是一个开源项目:
项目页面https://github.com/JSQLParser/JSqlParser包含wiki以及如何开始使用JSqlParser的示例。
在线文档可在https://javadoc.io/doc/com.github.jsqlparser/jsqlparser最新/index.html。pom.xml文件已经有一个JSqlParser依赖项。您不需要使用JSqlParser,但您需要正确解析第2.1节中定义的所有有效查询。如果您确实使用了JSqlParser,您应该自己使用它并阅读用于理解其输出的对象的结构的文档。
为了让您开始,我们在LightDB.java中提供了一个简单的方法,它使用JSqlParser从文件中读取SQL查询并将其打印出来。此方法说明使用JSqlParser和一些方法访问Statement对象的字段,例如如果语句是Select,则为getSelectBody()。您可以假设我们将使用的所有语句都是Selects,并且具有Plain Select作为selectBody。看看PlainSelect Javadocs;第一个FROM子句中的表将在fromItem中,其余的将在联接中。与您相关的还有where子句的where字段和不同的orderByElements,和groupByElements字段。编写一些SQL查询并编写代码以访问和打印为您的查询找出所有这些对象/字段,以了解“什么在哪里”。课程课业继续。
INFR11199(2024春季)课业第9页,共17页PlainSelect的where字段包含一个表达式;看一下的文档那个对于这个项目,您只需要担心AndExpression、LongValue、Column、,乘法(用于SUM聚合)、EqualsTo、NotEqualsTo、GreaterThan、,GreaterThanEquals、MinorThan和MinorThanEqual。这些捕获递归表达式的结构。前面提到的最后六种表达式类型是比较表达式,AndExpression是另外两个表达式的结合LongValue是一个数字文字,Column是一个列引用(例如中的S.idS.id<5)。每个Column对象都有一个列名,以及一个嵌入的Table对象。每个表对象都有一个名称和一个别名(如果使用了别名)。SUM合计是Function类型的表达式。
JSqlParser还提供了许多访问者接口,您可以选择也可以不选择选择使用。特别是ExpressionVisitor和ExpressionDeParser建议在到达选择操作符后使用。还可以查看wiki页面关于如何计算表达式的JSqlParser。
以上内容应该足以让你开始,但你应该期待做得更远
随着您实现越来越多的SQL功能,您可以自己进行探索。3.2机具扫描
您的第一个目标是支持全表扫描查询,例如SELECTFROMSailors(目前假设查询不使用别名)。为了实现这一点,您将需要实现您的第一个操作符&扫描操作符。
实现一个扩展Operator抽象类的ScanOperator。ScanOperator的每个实例都知道它是哪个基表表达式在此元组上为true或false。这最好使用表达式上的访问者来实现。你应该上课
它扩展了JSqlParser的ExpressionDeParser。该类将接受一个元组作为输入并递归地遍历表达式以在该元组上将其求值为true或false。这个表达式可能包含列引用——在我们的示例中,R.A<R.C AND R.B=42引用R的所有三列。访问者类需要一些方法来解析引用;即,如果我们的输入元组是(1,42,4),则需要一种方法来确定R.a是1等。因此,访问者类还需要接受一些模式信息。这取决于你如何
构造您的模式信息,但显然它必须允许从列进行映射
对元组中的索引的引用,如R.A。
编写完访问者类后,对其进行彻底的单元测试。从简单开始没有列引用的表达式,如1<2 AND 3=17。然后用测试列引用,直到您100%确定它有效为止。一旦你的表情评估逻辑是可靠的,您可以将其插入SelectOperator的getNextTuple()方法中。课程课业继续。
INFR11199(2024春季)课业第11页,共17页3.4实施投影
您的下一个任务是实现投影,即,您将能够处理的查询
form SELECT Sailors.id FROM Sailors WHERE Sailors.age=20。我们仍然假设查询不使用别名并且没有SUM聚合。
为了实现投影,您需要第三个操作符,即ProjectOperator。回想一下,袋子投影并不能消除重复。当getNextTuple()为调用时,它从其子元组中获取下一个元组,只将所需的值提取到新的元组中元组,并返回该元组。请注意,子项可能是SelectOperator或ScanOperator,具体取决于SQL查询是否包含WHERE子句。您可以从PlainSelect的selectItems字段中获取投影列。selectItems是SelectItem对象的列表,其中每个对象都是AllColumns(对于SELECT)或SelectExpressionItem。您可以假定中的表达式SelectExpressionItem将始终是列。一旦你抓住这些列需要将这些信息翻译成对项目运营商有用的东西。
请注意,SELECT中的属性顺序不必与属性匹配
表中的顺序。查询SELECT R.A,R.B FROM R和SELECT R.B,R.A FROMR都是有效的并且产生不同的输出结果。
到目前为止,您应该有代码接受SQL查询并生成查询计划包含:
一个可选的投影操作员,从小就有
一个可选的选择运算符,作为一个孩子
非可选扫描操作员。
因此,您的查询计划可以有一个、两个或三个运算符。确保你是支持所有可能性;尝试使用/不使用投影/选择的查询。如果查询是SELECT,不要创建投影运算符,如果查询没有WHERE子句,不要创建选择运算符。
您现在正在生成相对复杂的查询计划;然而,事情即将发生当我们添加联接时,会变得更加令人兴奋和混乱。现在是退出的好时机用于将查询计划构建到其自己的类中的逻辑(如果您还没有这样做的话)。因此,您应该有一个顶级解释器类,用于从
查询文件。您还应该有一个知道如何构造查询计划的第二个类对于语句,并将查询计划返回给解释器,从而使解释器
可以将查询计划的结果转储到某个地方。
课程课业继续。
INFR11199(2024春季)课业第12页,共17页3.5实施Join
接下来,该节目的明星:加入。假设仍然没有表别名,所以您现在不必担心自加入。
您需要一个同时具有左侧和右侧子运算符的JoinOperator。它还具有捕获联接条件的表达式。此表达式可以是
单个比较,例如R.A=S.B(或任何其他比较运算符,而不仅仅是=),A比较的连接(AND),或者如果连接是叉积,则可能为null。实现简单(元组)嵌套循环联接算法:联接应扫描左侧
(外部)子级一次,对于外部子级中的每个元组,它应该扫描内部子级完全(最后使用reset()方法!)。一旦操作员获得来自外部的元组和来自内部的元组,它将它们粘合在一起。如果有非null联接条件,只有当元组与联接条件匹配时才会返回(因此您将重用第3.3节中的表达式访问者类)。如果连接是十字架乘积,则返回所有元组对。
一旦您实现并单元测试了JoinOperator,您需要了解如何将SQL查询转换为包含联接的计划。
对于这个项目,我们要求您构建一个左深连接树,该树遵循FROM子句中的顺序。也就是说,FROM子句为FROM R,S,T的查询生成平面图,结构如下:
R“S”
T
./
棘手的部分是处理WHERE子句以提取联接条件。这个WHERE子句可以同时包含对单个表的选择以及联接条件链接多个表。例如,其中R.A<R.B AND S.C=1 AND R.D=S.G包含R上的选择表达式、S上的选择表达和联接条件
同时在R和S上。显然,将选择评估为
尽早,并在计算连接时评估R.D=S.G,而不是
计算叉积并稍后进行选择。
虽然这部分的重点不是优化,但您不想计算交叉
产品,除非你不得不这样做,因为这是非常低效的。因此,我们要求您有一些从WHERE子句中提取联接条件并进行求值的策略作为联接的一部分。你不需要很聪明,但你可以
而不是简单地计算叉积(当然,除非查询实际要求
课程课业继续。
INFR11199(2024春季)课业第13页,共17页交叉乘积)。您必须在代码和中的注释中解释您的策略
与代码一起提交的自述文件。
建议的方法是编写另一个扩展ExpressionDeParser的类并处理WHERE子句。对于每个连接词,访问者决定哪些表并将连词添加到适当的表达式中。如果有k
要联接的表,可能有2k1个运行表达式:k1个联接条件以及在各个表上的k个选择条件。一旦整个WHERE子句经过处理,2k1表达式可以集成到适当的选择中,并且联接查询计划中的运算符。当然,其中一些表达式可能会变成为null,具体取决于查询。
例如,如果我们有SELECTFROM R,S,T,其中R.A=1 AND R.B=S.CAND T.G<5 AND T.G=S.H,上述方法将给出以下查询计划:S
R
T
R.A=1
T.G<5/R.B=S.C
./T.G=S.H
你不必完全遵循这个策略;你可以寻求其他方式
提取联接条件。
3.6实施别名
下一步是实现别名以支持SELECT R.A FROM等查询SometableR。这些在任何情况下都很方便,但对于支持自联接来说是必不可少的。别名本身来自from子句,您可以从中提取它们
fromItem和PlainSelect的联接。不幸的是,当你提到列,JSqlParser不够聪明,无法知道
无论您使用的是别名还是引用。因此,如果你有一个SELECT R.aR.A作为Column返回,嵌入的Table对象将R作为表名无论R是基表名还是别名。因此,您需要跟踪
这些东西你自己。当您开始构建查询计划时,您需要确定查询是否使用别名。如果是,则需要跟踪中使用的所有别名查询,这样您就可以解析整个代码中的列引用。
课程课业继续。
INFR11199(2024春季)课业第14页,共17页实现别名在概念上并不困难,但您可能会发现它有点麻烦。它是对代码的干净程度和模块化程度的一次伟大测试;如果你一直在构建它那么,您将不得不修改相对较少的代码。
从仅在单表查询上支持别名开始可能很有用,然后
继续加入。一定要在包括自联接在内的许多查询上测试代码,因为当每个基表只使用一次时,可能会带来不明显的错误。而且确保您仍然可以正确地处理您测试的所有“旧”查询(不使用别名)。
3.7执行ORDER BY
接下来是ORDER BY运算符。您将通过添加一个排序运算符来实现ORDER BY。这将读取其子级的所有输出,将其放入内部缓冲区,排序它,然后在请求时返回单个元组。您可以使用Collections.sort();您将需要一个自定义比较器来指定不同的排序顺序。
您可能会对上述描述感到震惊。是的,sort是一个阻塞运算符,它意味着在产生任何输出之前,它确实需要看到所有的输入(想想看–如果所需排序顺序中最先出现的元组是子元组的最后一个元组,该怎么办接线员会吐出来吗?)。正如您所想象的,缓冲内存中的所有元组将不适用于大量的元组;对于这个项目任务,这很好。
如果您的查询有ORDER BY子句,则应将SortOperator作为根,他们在这个项目中。3.8实施DISTINCT
要添加对重复消除和DISTINCT的支持,您将添加一个新的运算符DuplicateEliminationOperator。您可以自由选择基于排序的或此运算符的基于哈希的实现。
3.9使用SUM聚合实现GROUP BY
要实现的最后一个运算符是使用SUM函数进行聚合分组。总和函数可以出现在SELECT子句的末尾、所有选定的属性之后,并且可以将一个项(整数或列)或项的乘积作为自变量。课程课业继续。
INFR11199(2024春季)课业第15页,共17页您将通过聚合运算符SumOperator实现一个组,它读取其子级的所有输出,将相关值提取到元组中,将元组组织到组,并为每个组计算一个聚合值。求和运算符需要查看
它在产生任何输出之前的所有输入(即它是阻塞运算符)。4任务2:查询优化
最后一项任务是通过查询优化来丰富LightDB。查询优化的目标是转换查询计划,使其运算符处理尽可能少的元组可能,从而减少处理时间并避免大的中间结果;然而这样优化的查询计划仍必须产生正确的查询结果。为了实现这一目标,您必须保持相同的联接顺序,但允许转换查询计划,例如,交换运算符或引入上面讨论的非联接运算符的新实例。你不应实现任何新的关系代数运算符。
适当优化的查询计划应避免处理大型中间结果
只要可能,这样就可以在内存受限的情况下执行此类计划预算和时间限制。我们将通过以下方式评估您的优化规则的有效性在大型数据库上运行一组查询。未能正确优化输入查询
很可能会导致错误的结果、内存不足异常或超时。
任务2不是要提高单个关系代数运算符的性能,而是要为有效的SQL聚合类制定优化规则查询,如第2.1节所述。一些优化规则将在讲座中介绍,但是有些需要你思考一下如何缩小中间体的尺寸
查询处理期间的结果。
5分级
我们强烈建议您遵循我们描述的体系结构。但是,我们不会对做出不同体系结构决策的人进行处罚,但有几个例外:必须具有实现getNextTuple()和reset()的关系运算符方法如上所述。这是标准的关系代数评估
模型,你需要学习它。不要硬接线组合运算符,
例如,投影不应假定选择是其子项(即,强制抽象)。
您必须构建一个运算符树,然后通过重复调用对其进行评估对根运算符执行getNextTuple()。
如第3.5节所述,必须按照
FROM子句中表的排序。此外,您必须有一个策略来识别课程课业继续。
INFR11199(2024春季)课程课业第16页,共17页联接条件,并将其作为联接的一部分进行评估,而不是进行选择在一个叉积之后。
无视上述三项要求中的任何一项都将导致严重的扣分。
接下来我们给出分级明细。
5.1代码风格和注释(10分)
遵循编写清晰易懂代码的标准指南;例如,使用标准
类和方法的命名约定,分解大块代码
分成更小的逻辑部分,尽可能避免代码重复——“三条规则”规定如果您的代码被复制了两次以上,那么可能需要将其抽象出来。您必须为实现的每个方法提供注释。注释至少必须包含一句关于方法目的的话,以及@params/@return分别为每个参数/返回值添加注释。此外,每节课都必须有一个描述类和类中使用的任何算法的逻辑的注释。
如果您遵循上述规则,并按照我们的总体要求编写合理干净的代码架构,您可能会在代码风格方面获得满分10分。
5.2测试查询(90分)
有关预期输入和输出格式的信息,请务必仔细阅读第2.2节。我们将在自己的查询和数据库上运行您的代码。我们提供的查询其中分配计数为90个点中的24个。您可以期待我们将添加数据库的附加表;当然会提到这些表的模式
在schema.txt中,数据文件将在数据目录中找到。任务1值60分,而任务2值30分。任何优化规则
您为任务2实现的必须是正确的,因此为任务1启用它们是可以的。我们将使用基本查询以及任意复杂的查询进行测试,这些查询包括您要实现的任何/所有功能。我们也可以重新排序我们给出的查询您和/或将它们与我们自己的穿插在一起,所以不要在上硬编码任何功能假设查询将按任何特定顺序运行。
如果你不能实现一个或多个运算符,那也没关系,尽管很明显你不会得到满分。在这种情况下,您必须在自述中清楚地告诉我们您未能实施。
课程课业继续。
INFR11199(2024春季)课业第17页,共17页6提交说明
仔细检查您的代码是否按照第2.2节中的说明编译和运行。如果您的代码未能编译或在执行过程中崩溃,我们将投入合理的努力来修复问题这可能会导致(严重的)扣分。
您必须将LightDB类保留为代码的顶级主类。
创建一个包含以下信息的自述文本文件。
对于任务1,解释从中提取联接条件的逻辑
WHERE子句。如果这个逻辑在代码的注释中得到了充分的解释README不需要重复这一点;然而,它必须确切地提到在哪里在代码/注释中有描述,所以评分者可以很容易地找到它。对于任务2,解释您的优化规则,解释它们正确的原因,以及它们如何在查询评估期间减小中间结果的大小。
您希望分级员了解的任何其他信息,例如已知的错误。
创建一个包含自述文件和整个项目文件夹的.zip档案,以便我们可以在命令行上编译和运行您的代码。不包括任何.class文件或大型.csv文件。在将代码提交到之前禁用所有调试语句允许我们使用大型数据集测试您的解释器。不这样做可能会导致扣分演绎
上传zip档案以了解:评估→ CW1编程分配
屈服
请记住,这是一项个人课业,而不是一个团队项目。你的作品将被审查是否有抄袭的迹象。
一定要早点出发!祝你好运
课程课业结束