What’s more
山东大学 2020级数据库系统 实验一
山东大学 2020级数据库系统 实验二
山东大学 2020级数据库系统 实验三
山东大学 2020级数据库系统 实验四
山东大学 2020级数据库系统 实验五
山东大学 2020级数据库系统 实验六
山东大学 2020级数据库系统 实验七
山东大学 2020级数据库系统 实验八、九
写在前面
做数据库实验一定要静得下心来,才能发现其中的错误然后进行改正。同时,如果发现 SQL 语句总是报错,“一定是你错了,只是不知道错在哪里!”
其次,SQL 语句中较为复杂的点博主都进行了注释,希望大家一定要看懂思路后自己写一遍,而不是盲目的 Ctrl+C,Ctrl+V,切记切记!!
实验七
本实验所考察的内容主要是关于索引,索引的建立一般有以下需要注意的点:
· 避免在取值朝一个方向增长的字段(例如:日期类型的字段)上,建立索引;对复合索引,避免将这种类型的字段放置在最前面。由于字段的取值总是朝一个方向增长,新记录总是存放在索引的最后一个叶页中,从而不断地引起该叶页的访问竞争、新叶页的分配、中间分支页的拆分。此外,如果所建索引是聚集索引,表中数据按照索引的排列顺序存放,所有的插入操作都集中在最后一个数据页上进行,从而引起插入“热点”。
· 对复合索引,按照字段在查询条件中出现的频度建立索引。在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用。因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。
建立索引的格式:create index index_name on table(name);
- 7-1
1. 将pub用户下表student的3个列sid,name,birthday复制到表test7_01中。
2. 执行如下查询,观察运行速度(5秒以上)。
查询Samefirstname相同姓氏的人数。
select * from
(select sid,name,birthday,
(select count(*) from test7_01 where substr(name,1,1)=substr(t1.name,1,1)) samefirstname
from pub.student_testindex t1)
where samefirstname=7
3. 为test7_01创建一个仅仅一个索引,保证上面SQL耗时在1秒内。
4. 交卷验证
思路:- 在什么上建立索引往往取决于 where 中的判断条件。一般判断条件是什么,就在什么上建立索引;
- 因此本题中在 substr(name, 1, 1) 上建立索引即可;
create index firstname_index on test7_01(substr(name, 1, 1))
- 7-2
1. 将pub用户下表student的3个列sid,name,birthday复制到表test7_02中。
2. 将出生日期全部修改成一天:
Update test7_02 set birthday=to_date(‘19881018’,‘yyyymmdd’) where substr(sid,12,1)=‘0’;
3. 为test7_02创建一个仅仅一个索引,保证下面SQL耗时在1秒内。
Samenamebirthday同名同生日的人数,Samebirthday相同出生日期的人数
select * from
(select sid,name,birthday,
(select count() from test7_02 where name=t1.name and birthday=t1.birthday) samenamebirthday,
(select count() from test7_02 where birthday=t1.birthday) samebirthday
from pub.student_testindex t1)
where samebirthday=403
4. 交卷验证
5. 思考题,test7_02不增建索引情况下,下面这个查询能使用索引吗?改进后能使用索引吗?
select * from
(select sid,name,birthday,
(select count(*) from test7_02 where name=t1.name) samename
from pub.student t1)
where samename=7
思路:- 根据上面所提到的原则:应用频度高的字段应放在复合索引的前面;由于我们把生日都设在了同一天,因此 birthday 才是应用频度最高的字段,应将其放在第一个;(前提条件是 where 中即用了 name 来查询,也用了 birthday 来查询)
create index name_birthday_index on test7_02(birthday, name)
接下来是根据索引修改条件的题目,基本原则就是:建立了索引的属性在 where 子句中要保持原样,运算符号 >, <, = 左边不能对它进行运算,也不能对它使用函数等操作
- 7-3
1. pub用户下表student已经用下面两句SQL创建了两索引。
Create index student_birthday on student(birthday);
Create index student_name on student(name);
2. 下面SQL不能用索引耗时超过2秒,在逻辑不变情况下,修改SQL中标为记红色的子查询的where条件部分,不要修改其它地方,使其能使用索引。
说明:因为pub.student_testindex数据行数太少,不能通过修改主句where绕过问题。
查询samefirstname同姓氏的人数。
select * from
(select sid,name,birthday,
(select count(*) from pub.student
where substr(name,1,1)=substr(t1.name,1,1)
) samefirstname
from pub.student_testindex t1) where samefirstname=7
3. 修改以后验证耗时在2秒之内,将修改以后语句创建成视图create view test7_03 as select ……。
4. 交卷验证
思路:- 该问需要查询同姓的学生信息,可以使用模糊查询 like 来进行,但需要注意怎样将“姓”和“%”进行连接呢?
- 想到了 rpad(str1, position, str2) 函数,表示在 str1 的右边第三个字节的位置连接 str2 字符,这样便可实现该功能;(或者 concat 函数也可以连接字符串)
create view test7_03 asselect * from(select sid,name,birthday,(select count(*) from pub.studentwhere name like rpad(substr(t1.name, 1, 1), 3, '%')) samefirstname from pub.student_testindex t1) where samefirstname=7
-
7-4
1. pub用户下表student已经用下面两句SQL创建了两索引。
Create index student_birthday on student(birthday);
Create index student_name on student(name);
2. 下面SQL不能用索引耗时超过1秒,在逻辑不变情况下,修改SQL中标为记红色的子查询的where条件部分,不要修改其它地方,使其能使用索引。
说明:因为pub.student_testindex数据行数太少,不能通过修改主句where绕过问题。
select * from
(select sid,name,birthday,
(select count() from pub.student
where to_char(birthday,‘yyyymm’)=to_char(t1.birthday,‘yyyymm’)
) sameyearmonth,
(select count() from pub.student
where extract (year from birthday) =extract (year from t1.birthday)
) sameyear
from pub.student_testindex t1) where sameyearmonth=35
3. 修改以后验证耗时在1秒之内,将修改以后语句创建成视图create view test7_04 as select ……。
4. 交卷验证
函数介绍:- trunc(t1.birthday, ‘mm’) – 获取当前日期月份的第一天;
- last_day(t1.birthday) – 获取当前日期月份的最后一天;
- trunc(t1.birthday, ‘yyyy’) – 获取当前日期年的第一天;
- add_months(date, number) – 在 date 上加 number 个月;
思路:
1. 本问需要求的是同年月以及同年的学生的 sid, name, birthday;
2. 同年月的学生的生日应该在当月的第一天和当月最后一天之间,trunc(t1.birthday, ‘mm’) 得到第一天,last_day(t1.birthday) 得到最后一天,使用 between 连接即可;
3. 同年的学生的生日应该在当年的第一天和当年最后一天之间,trunc(t1.birthday, ‘yyyy’) 得到当年的第一天,add_months(trunc(t1.birthday, ‘yyyy’), 12) 得到后一年的第一天,再 -1 得到当年的最后一天;
create view test7_04 asselect * from (select sid,name,birthday,(select count(*) from pub.student where birthday between (trunc(t1.birthday, 'mm')) and last_day(t1.birthday)) sameyearmonth,(select count(*) from pub.studentwhere birthday between (trunc(t1.birthday, 'yyyy')) and add_months(trunc(t1.birthday, 'yyyy'), 12) - 1) sameyearfrom pub.student_testindex t1) where sameyearmonth=35
- 7-5
1. pub用户下表student已经用下面两句SQL创建了两索引。
Create index student_birthday on student(birthday);
Create index student_name on student(name);
2. 下面SQL不能用索引耗时超过1秒,在逻辑不变情况下,修改SQL中标为记红色的子查询的where条件部分,不要修改其它地方,使其能使用索引。
说明:因为pub.student_testindex数据行数太少,不能通过修改主句where绕过问题。
查询nextbirthday晚一天出生的人数
select * from
(select sid,name,birthday,
(select count(*) from pub.student
where birthday-1=t1.birthday
) nextbirthday
from pub.student_testindex t1) where nextbirthday=7
3. 修改以后验证耗时在1秒之内,将修改以后语句创建成视图create view test7_05 as select ……。
4. 交卷验证
思路:- 由于不能对建立了索引的属性进行运算等操作,因此直接把 birthday-1 = t1.birthday 改成 birthday = t1.birthday + 1 即可;
select * from
(select sid,name,birthday,
(select count(*) from pub.student
where birthday = t1.birthday + 1
) nextbirthday
from pub.student_testindex t1) where nextbirthday=7
再次强调:一定是看懂思路之后自己实践哈~~
有问题还请斧正!