数据库实验
一.实验环境
1. 系统:win7 64位(虚拟机)
2. 处理器:Inter(R)Core(TM)i5-6267U [email protected]
3. 内存:4G
4. 数据库:oracle 12c
5. 运行SQL环境:navicat 和sql plus
二.实验数据
1. 数据来源:tpc-h数据集
2. 数据详情:
一共有8张表分别是(数据量从小到大):
(1) Region表 5条数据
名 |
类型 |
长度 |
含义 |
是否null |
R_REGIONKEY |
NUMBER |
0 |
地区key值 |
NOT NULL |
R_NAME |
CHAR |
25 |
地区名 |
NOT NULL |
R_COMMENT |
VARCHAR |
152 |
地区细节 |
|
(2) Nation表 25条数据
名 |
类型 |
长度 |
含义 |
不是null |
N_NATIONKEY |
INTEGER |
0 |
国家key值 |
NOT NULL |
N_NAME |
CHAR |
25 |
国家名 |
NOT NULL |
N_REGIONKEY |
INTEGER |
0 |
所属地区key值 |
NOT NULL |
N_COMMENT |
VARCHAR |
152 |
国家细节 |
|
(3) Supplier表 10000条
名 |
类型 |
长度 |
含义 |
不是null |
S_SUPPKEY |
INTEGER |
0 |
供应商key值 |
NOT NULL |
S_NAME |
CHAR |
25 |
供应商名 |
NOT NULL |
S_ADDRESS |
VARCHAR |
40 |
供应商地址 |
NOT NULL |
S_NATIONKEY |
INTEGER |
0 |
供应商国家key |
NOT NULL |
S_PHONE |
CHAR |
15 |
供应商电话 |
NOT NULL |
S_ACCTBAL |
DECIMAL (15,2) |
15 |
账户结余 |
NOT NULL |
S_COMMENT |
VARCHAR |
101 |
细节 |
NOT NULL |
(4) Part表 20万条
名 |
类型 |
长度 |
含义 |
不是null |
P_PARTKEY |
INTEGER |
0 |
零件key值 |
NOT NULL |
P_NAME |
VARCHAR(55) |
55 |
零件名 |
NOT NULL |
P_MFGR |
CHAR |
25 |
供应商名 |
NOT NULL |
P_BRAND |
CHAR |
10 |
品牌 |
NOT NULL |
P_TYPE |
VARCHAR |
25 |
零件类型 |
NOT NULL |
P_SIZE |
INTEGER |
0 |
大小 |
NOT NULL |
P_CONTAINER |
CHAR |
10 |
容器货柜 |
NOT NULL |
P_RETAILPRICE |
DECIMAL(15,2) |
15 |
零售价 |
NOT NULL |
P_COMMENT |
VARCHAR |
23 |
细节 |
NOT NULL |
(5) Customer表 15万条
名 |
类型 |
长度 |
含义 |
不是null |
C_CUSTKEY |
INTEGER |
0 |
消费者key值 |
NOT NULL |
C_NAME |
VARCHAR |
25 |
消费者名 |
NOT NULL |
C_ADDRESS |
VARCHAR |
40 |
消费者地址 |
NOT NULL |
C_NATIONKEY |
INTEGER |
0 |
消费者国家key |
NOT NULL |
C_PHONE |
CHAR |
15 |
消费者电话 |
NOT NULL |
C_ACCTBAL |
DECIMAL(15,2) |
15 |
消费者账户结余 |
NOT NULL |
C_MKTSEGMENT |
CHAR |
10 |
市场划分 |
NOT NULL |
C_COMMENT |
VARCHAR |
117 |
细节 |
NOT NULL |
(6) Partsupp表 80万条
名 |
类型 |
长度 |
含义 |
不是null |
PS_PARTKEY |
INTEGER |
0 |
零件key |
NOT NULL |
PS_SUPPKEY |
INTEGER |
0 |
供应商key |
NOT NULL |
PS_AVAILQTY |
INTEGER |
0 |
平均数量 |
NOT NULL |
PS_SUPPLYCOST |
DECIMAL(15,2) |
15 |
供应成本 |
NOT NULL |
PS_COMMENT |
VARCHAR |
199 |
细节 |
NOT NULL |
(7) Orders表 150万条
名 |
类型 |
长度 |
含义 |
不是null |
O_ORDERKEY |
INTEGER |
0 |
订单key |
NOT NULL |
O_CUSTKEY |
INTEGER |
0 |
消费者key |
NOT NULL |
O_ORDERSTATUS |
CHAR |
1 |
订单状态 |
NOT NULL |
O_TOTALPRICE |
DECIMAL(15,2) |
15 |
订单总价 |
NOT NULL |
O_ORDERDATE |
DATE |
|
订单日期 |
NOT NULL |
O_ORDERPRIORITY |
CHAR |
15 |
订单优先级 |
NOT NULL |
O_CLERK |
CHAR |
15 |
销售员 |
NOT NULL |
O_SHIPPRIORITY |
INTEGER |
0 |
发货优先级 |
NOT NULL |
O_COMMENT |
VARCHAR |
79 |
细节 |
NOT NULL |
(8) Lineitem表(在线商品) 6,001,215条
名 |
类型 |
长度 |
含义 |
不是null |
L_ORDERKEY |
INTEGER |
0 |
订单key |
NOT NULL |
L_PARTKEY |
INTEGER |
0 |
零件key |
NOT NULL |
L_SUPPKEY |
INTEGER |
0 |
供应商key |
NOT NULL |
L_LINENUMBER |
INTEGER |
0 |
在线号码 |
NOT NULL |
L_QUANTITY |
DECIMAL(15,2) |
15 |
数量 |
NOT NULL |
L_EXTENDEDPRICE |
DECIMAL(15,2) |
15 |
折扣价 |
NOT NULL |
L_DISCOUNT |
DECIMAL(15,2) |
15 |
折扣 |
NOT NULL |
L_TAX |
DECIMAL(15,2) |
15 |
税 |
NOT NULL |
L_RETURNFLAG |
CHAR |
1 |
|
NOT NULL |
L_LINESTATUS |
CHAR |
1 |
在线状态 |
NOT NULL |
L_SHIPDATE |
DATE |
|
发货日期 |
NOT NULL |
L_COMMITDATE |
DATE |
|
提货日期 |
NOT NULL |
L_RECEIPTDATE |
DATE |
|
接收日期 |
NOT NULL |
L_SHIPINSTRUCT |
CHAR |
25 |
装运指示 |
NOT NULL |
L_SHIPMODE |
CHAR |
10 |
运输形式 |
NOT NULL |
L_COMMENT |
VARCHAR |
44 |
细节 |
NOT NULL |
3. 表结构关系图
4. TPC-H标准定义的模式图
三.分区表实验(实验一)
1. 分区表:当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会下降,这时就应该考虑对表进行分区。表进行分区后,逻辑上表仍然是一张完整的表,只是将表中的数据在物理上存放到多个表空间(物理文件上),这样查询数据时,不至于每次都扫描整张表。
2. 分区表优点:
(1) 改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。
(2) 增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;
(3) 维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;
(4) 均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能。
3. 问题汇总
(1)没有建分区表前的速度?建好分区表之后的性能?不同分区方法?
(2)为什么他快?
(3)新增问题:
在建表时候没有使用分区表怎么办?普通表如何转化为分区表?
4. 分区实验
(1)使用的表是:ORDERS(150万条数据)
(2)测试的sql语句
1.SELECT *FROM ORDERS WHERE O_TOTALPRICE>10000;
2.SELECT *FROM ORDERS WHERE O_ORDERDATE
between to_date('1994-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')
and to_date('1995-12-31 00:00:00','yyyy-mm-dd hh24:mi:ss');
3. SELECT *FROM ORDERS WHERE O_ORDERKEY>100000 AND O_CUSTKEY<200000;
4. SELECT *FROM ORDERS WHERE O_ORDERSTATUS='O';
5. SELECT *FROM ORDERS WHERE O_CLERK LIKE 'Clerk#0000003%';
(3)分区表sql:
(4)对比图: 单位:秒 第一格为第一次查询结果,第二格是第二次的结果
Sql语句 |
没有建立分区表的速度 |
建立时间分区表的速度 |
建立hash分区表的速度 |
|||
sql语句1 |
37.781 |
29.163 |
27.242 |
23.529 |
26.157 |
22.358 |
sql语句2 |
8.5000 |
8.001 |
7.816 |
7.798 |
10.408 |
8.039 |
sql语句3 |
24.611 |
23.906 |
23.872 |
23.255 |
24.075 |
23.078 |
sql语句4 |
11.673 |
13.214 |
11.280 |
11.713 |
11.354 |
11.298 |
Sql语句5 |
3.433 |
2.813 |
3.228 |
3.104 |
3.133 |
3.028 |
5. 原因分析
(1)为什么他快?
在测试完之后,并没有感觉快多少,甚至,hash分区的效率甚至不如没有建立分区表;分区表的本质应该是降低I/O。
(2)在建表时候没有使用分区表怎么办?普通表如何转化为分区表?
在做这个实验的时候发现一开始不是很理解是怎么做,一开始以为是在原表的基础上做分区表,后来发现并不是这样,但是当原表没有建立分区表的时候也是可以补救的。
普通表转化为分区表:
1. Export/import method
这种方法就是使用insert 来实现。 当然在创建分区表的时候可以一起插入数据,也可以创建好后在insert 进去。 这种方法采用DDL语句,不产生UNDO,只产生少量REDO,建表完成后数据已经在分布到各个分区中。
2. Insert with a subquery method
利用原表重建分区表,这种方法的特点是:
优点:方法简单易用,由于采用DDL语句,不会产生UNDO,且只产生少量REDO,效率相对较高,而且建表完成后数据已经在分布到各个分区中了。
不足:对于数据的一致性方面还需要额外的考虑。由于几乎没有办法通过手工锁定T表的方式保证一致性,在执行CREATE TABLE语句和RENAME T_NEW TO T语句直接的修改可能会丢失,如果要保证一致性,需要在执行完语句后对数据进行检查,而这个代价是比较大的。另外在执行两个RENAME语句之间执行的对T的访问会失败。
适用于修改不频繁的表,在闲时进行操作,表的数据量不宜太大。
主要有2种方式,ctas和insert方式
3. Partition exchange method
利用交换分区的方法这种方法的特点
优点:只是对数据字典中分区和表的定义进行了修改,没有数据的修改或复制,效率最高。如果对数据在分区中的分布没有进一步要求的话,实现比较简单。在执行完RENAME操作后,可以检查T_OLD中是否存在数据,如果存在的话,直接将这些数据插入到T中,可以保证对T插入的操作不会丢失。
不足:仍然存在一致性问题,交换分区之后RENAME T_NEW TO T之前,查询、更新和删除会出现错误或访问不到数据。如果要求数据分布到多个分区中,则需要进行分区的SPLIT操作,会增加操作的复杂度,效率也会降低。
适用于包含大数据量的表转到分区表中的一个分区的操作。应尽量在闲时进行操作
4. DBMS_REDEFINITION
利用在线重定义这种分区的特点
优点:保证数据的一致性,在大部分时间内,表T都可以正常进行DML操作。只在切换的瞬间锁表,具有很高的可用性。这种方法具有很强的灵活性,对各种不同的需要都能满足。而且,可以在切换前进行相应的授权并建立各种约束,可以做到切换完成后不再需要任何额外的管理操作。
不足:实现上比上面两种略显复杂。
适用于各种情况。
在线重定义的大致操作流程如下:
(1)创建基础表A,如果存在,就不需要操作。
(2)创建临时的分区表B结构。
(3)开始重定义,将基表A的数据导入临时分区表B。
(4)结束重定义,完成后在DB的Name Directory里,已经将2个表进行了交换。即此时基表A成了分区表,我们创建的临时分区表B 成了普通表。 此时我们可以删除我们创建的临时表B。它已经是普通表。
四.索引实验(实验二)
1.索引:索引是建立在表的一列或多个列上的辅助对象,目的是加快访问表中的数据;
Oracle存储索引的数据结构是B*树(平衡树),位图索引也是如此,只不过是叶子节点不同B*数索引;
索引由根节点、分支节点和叶子节点组成,上级索引块包含下级索引块的索引数据,叶节点包含索引数据和确定行实际位置的rowid。
2.索引建设原则
(1)索引应该经常建在Where 子句经常用到的列上。如果某个大表经常使用某个字段进行查询,并且检索行数小于总表行数的5%。则应该考虑。
(2)、对于两表连接的字段,应该建立索引。如果经常在某表的一个字段进行Order By 则也经过进行索引。
(3)、不应该在小表上建设索引。
3.索引分类
B树索引、位图索引、哈希索引
单列索引和复合索引
4.实验问题及实验内容
1)使用索引和不使用索引时候速度对比;
2)结合分区,分区和索引对比
3)位图索引的优势体现;
5.实验数据
使用的orders表(150万条数据),customer表(15万条数据)
6.小实验一(B树索引)
(1)建立索引sql
CREATE INDEX index_orderkey ON ORDERS('O_ORDERKEY');
(2)测试使用的sql语句
1.SELECT *FROM ORDERS WHERE O_TOTALPRICE>10000;
2.SELECT *FROM ORDERS WHERE O_ORDERDATE
between to_date('1994-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')
and to_date('1995-12-31 00:00:00','yyyy-mm-dd hh24:mi:ss');
3.SELECT *FROM ORDERS WHERE O_ORDERKEY>100000 AND O_CUSTKEY<200000;
4.SELECT *FROM ORDERS WHERE O_ORDERSTATUS='O';
5.SELECT *FROM ORDERS WHERE O_CLERK LIKE 'Clerk#0000003%';
6.SELECT * FROM ORDERSBYTIME WHERE O_ORDERKEY>1000 AND O_ORDERKEY<20000;
(3)实验结果对比 时间:秒 第一次和第二次的时间
Sql语句 |
不使用索引 |
使用B树索引(用orderkey字段作为索引) |
||||||
|
没有建立分区表 |
建立hash分区表 |
没有建立分区表 |
建立hash分区表 |
||||
SQL语句1 |
37.781 |
29.163 |
26.157 |
22.358 |
42.896s |
24.980 |
30.309 |
23.292 |
SQL语句2 |
8.5000 |
8.001 |
10.408 |
8.039 |
7.370 |
7.776 |
7.662 |
8.127 |
SQL语句3 |
24.611 |
23.906 |
24.075 |
23.078 |
24.590 |
23.003 |
24.758 |
23.455 |
Sql语句4 |
11.673 |
13.214 |
11.354 |
11.298 |
12.333 |
11.395 |
12.123 |
10.964 |
Sql语句5 |
3.433 |
2.813 |
3.133 |
3.028 |
2.929 |
2.949 |
2.852 |
2.774 |
Sql语句6 |
0.281 |
0.306 |
0.415 |
0.340 |
0.339 |
0.261 |
0.389 |
0.309 |
(4)实验分析
没有得到显著的提高,索引不正确?数据量不够?只有细微的提高,感觉不正确。
换表重新测试使用LINEITEM 600万条数据
SELECT *FROM LINEITEM WHERE L_ORDERKEY>2513090;(第一次和第二次)
没有索引:158.972s 119.364
有索引: 121.647s 108.265
SELECT *FROM LINEITEM WHERE L_ORDERKEY=2513090;
没有索引:1.675s 1.442
有索引: 0.039 0.003
CREATE INDEX index_orderkey ON LINEITEM(L_ORDERKEY)
9.629s
可以看到,使用了索引之后速度提高很是明显。索引起作用了。至于之前的结果数据没有分析出原因。
7.实验二(位图索引)
1)使用使用LINEITEM 600万条数据
L_RETURNFLAG 这个字段只有:’N’,’A’,’R’
create index indexL1 on LINEITEM(L_RETURNFLAG);
create bitmap index indexL2 on LINEITEM(L_RETURNFLAG);
2)测试用sql语句
select *from LINEITEM where L_RETURNFLAG='N';
3)结果对比
Sql语句 |
没有索引 |
位图索引 |
B树索引 |
|||
语句1 |
101.857 |
89.541 |
101.722 |
115.794 |
87.867 |
86.332 |
4) 结果分析
位图索引没有提高查询速度,B树索引有所提高,但不大。
8索引实验总结
两次实验得到的结果都不是令人满意,没有找到原因。第一次实验的改进实验得到了意料中的结果,符合所学的知识。
索引主要进行提高数据的查询速度。 当进行DML时,会更新索引。因此索引越多,则DML越慢,其需要维护索引。 因此在创建索引及DML需要权衡。
五.Oracle绑定变量与非绑定变量对比(实验三)
1. 绑定变量:oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析.
一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要的们闩(latch)资源,严重的影响系统的规模的扩大(即限制了系统的并发行), 而且引起的问题不能通过增加内存条和cpu的数量来解决。
之所以这样是因为门闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改。当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。
而唯一使得oracle 能够重复利用执行计划的方法就是采用绑定变量。绑定变量的实质就是用于替代sql语句中的常量的替代变量。绑定变量能够使得每次提交的sql语句都完全一样。
2. 实验问题以及实验内容
(1) 绑定变量与没有绑定变量时候查询速度差异对比
(2) 分析原因
3. 实验数据
(1) Orders表(150万条数据),备用表Lineitem(600万条数据)
4. 实验代码截图
(1) 没使用绑定变量截图
(2)使用绑定变量截图
(3)实验结果分析
使用绑定变量和没用绑定变量速度几乎一样,怀疑是12c自动使用了绑定变量。重新设计一个实验。
(4)新实验
分别使用绑定变量和不使用绑定变量分别向表中插入10000条数据,测量所使用的时间
1.绑定变量的测试
2.没有使用绑定变量的测试
(5)新实验分析
还是没有显著的变化(只提高一倍?!),不知道,问题出在哪里。网上搜索寻找答案。
5. 实验总结
绑定变量是在通常情况下能提升效率,非正常的情况如下:
在字段(包括字段集)建有索引,且字段(集)的集的势非常大(也就是有个值在字段中出现的比例特别的大)的情况下,使用绑定变量可能会导致查询计划错误,因而会使查询效率非常低。这种情况最好不要使用绑定变量。
但是并不是任何情况下都需要使用绑定变量,下面是两种例外情况:
1.对于隔相当一段时间才执行一次的SQL语句,这是利用绑定变量的好处会被不能有效利用优化器而抵消
2.数据仓库的情况下。
绑定变量不能当作嵌入的字符串来使用,只能当作语句中的变量来用。不能用绑定变量来代替表名、过程名、字段名等.
从效率来看,由于oracle10G放弃了RBO,全面引入CBO,因此,在10G中使用绑定变量效率的提升比9i中更为明显。