一、索引
在 Oracle 数据库中,索引是一种数据结构,用于加快数据库表的数据检索速度。索引存储着表中一个或多个列的值以及对应的行的物理地址或指针。通过使用索引,数据库可以更快地定位到符合特定条件的行,而不必扫描整个表。索引是用于加速数据存取的数据对象。合理的使用索引可以大大降低 i/o 次数,从而提高数据访问性能。索引是需要占据存储空间的,也可以理解为是一种特殊的数据。形式类似于 下图的一棵“树”,而树的节点存储的就是每条记录的物理地址,也就是我们提到的伪列(ROWID)。
索引的选择取决于数据库的特定需求和查询模式。虽然索引可以显著提高查询性能,但过多或不合适的索引可能会增加写操作的开销,并占用额外的存储空间。因此,在设计索引时需要权衡查询性能和数据维护的成本。
1、普通索引
语法:
create index 索引名称 on 表名(列名); |
需求:我们经常要根据业主名称搜索业主信息,所以我们基于业主表的 name 字
段来建立索引。语句如下:
create index index_owners_name on t_owners(name) |
索引性能测试:
创建一个两个字段的表
create table t_indextest ( id number, name varchar2(30) ); |
编写 PL/SQL 插入 100 万条记录(关于 PL/SQL 我们在第四章会学到)
begin for i in 1 .. 1000000 loop insert into t_indextest values (i, 'dev' || i); end loop; commit; end; |
创建完数据后,根据 name 列创建索引
create index index_testindex on t_indextest(name); |
执行下面两句 SQL 执行
SELECT * from T_INDEXTEST where ID=765432; SELECT * from T_INDEXTEST where NAME= 'dev765432'; |
我们会发现根据 name 查询所用的时间会比根据 id 查询所用的时间要短
2、唯一索引
如果我们需要在某个表某个列创建索引,而这列的值是不会重复的。这是我们可以创建唯一索引。由于索引列的值 不重复 唯一索引的查询效率会更高 主键就是唯一索引
语法:
create unique index 索引名称 on 表名(列名); |
需求:在业主表的水表编号一列创建唯一索引
语句:
create unique index index_owners_watermeter on t_owners(watermeter); |
3、复合索引
我们经常要对某几列进行查询,比如,我们经常要根据学历和性别对学员进行搜 索,如果我们对这两列建立两个索引,因为要查两棵树,查询性能不一定高。那 如何建立索引呢?我们可以建立复合索引,也就是基于两个以上的列建立一个索引 。
语法:
create index 索引名称 on 表名(列名,列名.....); |
根据地址和门牌号对学员表创建索引,语句如下:
create index owners_index_ah on t_owners(addressid, housenumber); |
4、案例
-- 索引
-- 1 普通索引
-- 创建表 t_index_test
create table t_index_test
(id number,name varchar2(30)
);
-- 插入数据
beginfor i in 1 .. 10000000loopinsert into t_index_test values (i, 'dev' || i);end loop;commit;
end;
-- 验证性能 在虚拟机中set timing on可以开启sql执行时间检测
-- 没有索引的情况下 查询
select * from t_index_test where name = 'dev5555555';
-- 创建普通索引
-- create index 索引名 on 表名(索引字段);
create index index_test on t_index_test(name);
-- 验证性能 在虚拟机中set timing on可以开启sql执行时间检测
select * from t_index_test where name = 'dev5555555';-- 2 唯一索引
-- 唯一索引
-- 创建索引的字段必须数据不可重复(主键)
-- create unique index 索引名 on 表名(索引字段);
create unique index index_test2 on t_index_test(id);
-- 验证性能
select * from t_index_test where id = 5555555;-- 3 复合索引
-- 复合索引
create index index_test3 on t_index_test (id, name);
-- 验证性能
select * from t_index_test
where name = 'dev5555555' and id = 5555555;
二、权限
1、权限含义
在 Oracle 中,权限是指对数据库对象执行特定操作的授权。这些对象可以是表、视图、存储过程、包、序列等。授权权限给用户或角色允许他们执行特定的数据库操作。
以下是 Oracle 中常见的权限类型:
-
SELECT: 允许用户查询表或视图中的数据。
-
INSERT: 允许用户向表中插入新的行。
-
UPDATE: 允许用户修改表中已有行的数据。
-
DELETE: 允许用户删除表中的行。
-
EXECUTE: 允许用户执行存储过程、函数、包等数据库程序单元。
-
CREATE: 允许用户创建新的数据库对象,如表、视图、索引等。
-
ALTER: 允许用户修改现有的数据库对象的结构,如表结构的修改。
-
DROP: 允许用户删除数据库对象。
-
GRANT: 允许用户将自己拥有的权限授予其他用户或角色。
-
REVOKE: 允许用户撤销先前授予的权限。
这些权限可以通过 GRANT 和 REVOKE 语句进行授权和收回。用户可以直接被授予权限,也可以通过角色间接地获得权限。角色是权限的集合,可以被分配给用户,从而简化权限管理,提高安全性,并减少权限分配的复杂性。
2、案例
-- todo 11 权限的基本操作-- todo 1 创建用户 c##zhangfei
-- create user 用户名 identified by 密码;
create user c##zhangfei identified by itcast;
-- todo 1.1 赋予权限 登录用户
-- grant 权限 to 用户名;
grant dba to c##zhangfei;
-- todo 1.2 创建数据表
create table xxx(id number
);
-- todo 1.3 修改密码
-- alter user 用户名 identified by 新密码;
alter user c##zhangfei identified by itcast1;
-- todo 1.4 删除用户
-- 删除普通用户
-- drop user 用户名;
drop user c##zhangfei;
-- 删除有数据的用户
-- drop user 用户名 cascade ;
drop user c##zhangfei cascade ;-- todo 2 系统权限
-- 显示所有的系统权限
select * from system_privilege_map order by name;
-- todo 1.创建两个用户 caocao, liubei. 初始阶段他们没有任何权限,如果登陆就会给出错误的信息
-- todo 1.1创建两个用户,并指定密码
create user c##caocao identified by itcast;
create user c##liubei identified by itcast;
-- todo 2.给用户caocao授权:
-- todo 2.1:授子create session 和 create table权限时 带with admin option
grant create session,create table to c##caocao with admin option;
-- todo 2.2 授予create view 时不带with admin option
grant create view to c##caocao;
-- todo 3 在虚拟机上 登陆c##caocao给用户liubei授权
grant create session,create table to c##liubei;
grant create view to c##liubei;
-- todo 3.1 用户liubei登陆 验证是否具有create session,create table to和create view权限
-- todo 4.级联回收问题(不会产生级联回收)
-- 收回c##caocao的create session权限
revoke create session from c##caocao;-- todo 3 对象权限
-- 查看所有的数据表
select * from ALL_TABLES;
-- 查看所有对象权限
select distinct privilege from dba_tab_privs;
-- 案例1
-- todo 1.zhaoyun用户要操作wateruser.t_owners表,则必须授予相应的对象权限
create user c##zhaoyun identified by itcast;
grant create session to c##zhaoyun;
-- todo 2.希望zhaoyun可以查询wateruser.t_owners的表数据,怎样操作?
grant select on c##wateruser.t_owners to c##zhaoyun;
-- todo 3.希望zhaoyun可以修改wateruser.t_owners的表数据、怎样操作?
grant update on c##wateruser.t_owners to c##zhaoyun;
-- todo 4.希望zhaoyun可以删除wateruser.t_owners的表数据,怎样操作?
grant delete on c##wateruser.t_owners to c##zhaoyun;
-- 有没有更加简单的方法,一次把所有权限赋给zhaoyun?
grant select,delete,alter on c##wateruser.t_owners to c##zhaoyun;
-- todo 5.虚拟机 登陆zhaoyun 验证-- 案例2
-- todo 1 system操作 创建用户 yangjian 和 nazha
create user c##yangjian identified by itcast;
create user c##nazha identified by itcast;
-- todo 2 system操作: 给用户 yangjian 和 nazha 授权 create session
grant create session to c##nazha;
grant create session to c##yangjian;
-- todo 3 wateruser 登录,完成如下操作: 把对 t_owners 表的操作权利给 yangjian:
grant select on c##wateruser.T_OWNERS to c##yangjian with grant option;
-- todo 4 使用 yangjian 把权限给 nazha;
grant select on c##wateruser.T_OWNERS to c##nazha;
-- todo 5 使用 wateruser 将查询权限从yangjian 回收
revoke select on c##wateruser.T_OWNERS from c##yangjian;
-- todo 6 验证: yangjian 和 nazha 还能对 wateruser.t_owners 进行查询吗?
三、角色管理
1、角色管理含义
在 Oracle 中,角色管理是指管理和分配角色的过程。角色是一组权限的集合,可以被授予给用户或其他角色。通过角色管理,可以简化权限管理,提高安全性,并减少权限分配的复杂性。
角色管理涉及以下几个方面:
-
创建角色:数据库管理员可以创建新的角色,定义该角色拥有的权限集合。
-
授予角色:通过 GRANT 语句,数据库管理员可以将角色授予给用户或其他角色。授予角色相当于将该角色拥有的所有权限授予了被授予角色的用户或角色。
-
角色层级:角色之间可以存在层级关系,即一个角色可以包含另一个角色。被包含的角色拥有被包含角色的所有权限。这种角色的层级关系可以形成权限的继承链。
-
回收角色:通过 REVOKE 语句,数据库管理员可以从用户或其他角色身上收回已经授予的角色。
-
角色的管理:数据库管理员可以对角色进行管理,包括修改角色的权限集合、重命名角色、删除角色等操作。
-
角色的使用:用户可以使用 GRANT 和 REVOKE 语句将角色授予给自己或其他用户,以获取角色所包含的权限。
通过合理地使用角色管理,可以简化数据库权限管理的复杂性,并确保用户只拥有他们所需的最小权限,从而提高数据库的安全性和管理效率。
2、案例
-- todo 11 角色管理-- todo 1 预定义角色
-- connect角色
select * from dba_sys_privs where grantee='CONNECT';
-- resource角色
select * from dba_sys_privs where grantee='RESOURCE';
-- dba角色
select * from dba_sys_privs where grantee='DBA';-- 1 创建一个用户 jack
create user c##jack identified by itcast;
-- 2 将 jack 设为具有 DBA 角色的用户
grant dba to c##jack;-- todo 2 自定义角色
-- 1.显示所有角色
select * from dba_roles;
-- 2.显示用户具有的角色,及默认角
select granted_role from dba_role_privs where grantee='C##JACK';-- todo 1.创建用户 zhouyu, 并把某个角色 dev (具有create session,select on wateruser.t_owners杈限)赋给该用户.
drop user c##zhouyu cascade;
-- 创建角色 无序验证
create role c##dev not identified;
-- 给角色赋予权限
grant create session to c##dev;
grant select on c##wateruser.T_OWNERS to c##dev;
-- todo 2.创建用户 zhouyu
create user c##zhouyu identified by itcast;
-- todo 3.用sunquan给zhouyu赋角色dev
grant c##dev to c##zhouyu;
-- todo 4.测试 删除权限
revoke c##dev from c##zhouyu;
-- todo 5.测试 删除角色
drop role c##dev;
四、分区表
1、分区表概念
在 Oracle 中,分区表是指根据指定的条件将表中的数据分割成多个逻辑上独立的分区,每个分区可以单独进行管理。分区表的创建可以根据时间、范围、列表或哈希等分区键进行分割。分区表的主要优势包括:
-
性能提升:通过分区,可以实现数据的分布式存储和查询,从而提高查询性能。当查询仅涉及到某个分区的数据时,数据库可以只扫描该分区,而不是整个表。
-
管理简化:分区表使得数据管理变得更加灵活和简单。可以对每个分区进行单独的备份、恢复、移动和维护操作,而无需影响整个表。
-
数据保护:分区表可以提高数据的安全性和可用性。例如,可以将历史数据移动到单独的分区,并对其进行只读或归档,从而降低对常用数据的访问压力,并减少故障发生时的数据损失。
-
更好的查询性能:通过分区表,可以根据数据的访问模式进行优化,例如,可以将常用的数据存储在热分区,而将不常用的数据存储在冷分区,从而提高查询性能。
2、案例
-- todo 创建表空间
CREATE TABLESPACE part1_ts
DATAFILE 'C:\data\part1_ts_01.dbf' SIZE 10M,'C:\data\part1_ts_02.dbf' SIZE 10M,'C:\data\part1_ts_03.dbf' SIZE 10M;CREATE TABLESPACE part2_ts
DATAFILE 'C:\data\part2_ts_01.dbf' SIZE 10M,'C:\data\part2_ts_02.dbf' SIZE 10M,'C:\data\part2_ts_03.dbf' SIZE 10M,'C:\data\part2_ts_04.dbf' SIZE 10M;CREATE TABLESPACE part3_ts
DATAFILE 'C:\data\part3_ts_01.dbf' SIZE 10M,'C:\data\part3_ts_02.dbf' SIZE 10M,'C:\data\part3_ts_03.dbf' SIZE 10M,'C:\data\part3_ts_04.dbf' SIZE 10M,'C:\data\part3_ts_05.dbf' SIZE 10M;-- todo 1 范围分区表
-- 范围分区指定的字段 必须能够进行范围判断
-- todo 1.1 创建范围分区表
CREATE TABLE tb_order (order_id NUMBER PRIMARY KEY,customer_id NUMBER,order_date DATE,total_amount NUMBER(10, 2),status VARCHAR2(20)
)
PARTITION BY RANGE(order_id) (PARTITION orders_1 VALUES LESS THAN (1000) TABLESPACE part1_ts,PARTITION orders_2 VALUES LESS THAN (2000) TABLESPACE part2_ts,PARTITION orders_3 VALUES LESS THAN (MAXVALUE) TABLESPACE part3_ts
);
-- 插入数据到orders_1分区
INSERT INTO tb_order PARTITION (orders_1)
VALUES (1, 1001, TO_DATE('2023-01-01', 'YYYY-MM-DD'), 100.50, 'Pending');
-- 插入数据到orders_2分区
INSERT INTO tb_order PARTITION (orders_2)
VALUES (1001, 2001, TO_DATE('2023-02-01', 'YYYY-MM-DD'), 200.75, 'Processing');
-- 插入数据到orders_3分区
INSERT INTO tb_order PARTITION (orders_3)
VALUES (2001, 3001, TO_DATE('2023-03-01', 'YYYY-MM-DD'), 300.25, 'Completed');
-- 按照分区字段查找数据 可以加快查询速度
select * from tb_order where order_id=1;
-- 指定分区查数据
-- 从orders_1分区取数据
SELECT * FROM tb_order PARTITION (orders_1);
-- 从orders_2分区取数据
SELECT * FROM tb_order PARTITION (orders_2);
-- 从orders_3分区取数据
SELECT * FROM tb_order PARTITION (orders_3);
-- 查不到, 为什么?
SELECT * FROM tb_order PARTITION (orders_2)
where order_id=1;-- todo 1.2 按照时间范围分区
CREATE TABLE tb_order_2 (order_id NUMBER PRIMARY KEY,customer_id NUMBER,order_date DATE,total_amount NUMBER(10, 2),status VARCHAR2(20)
)
PARTITION BY RANGE(order_date) (PARTITION orders_2022 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD')) TABLESPACE part1_ts,PARTITION orders_2023 VALUES LESS THAN (TO_DATE('2024-01-01', 'YYYY-MM-DD')) TABLESPACE part2_ts,PARTITION orders_future VALUES LESS THAN (MAXVALUE) TABLESPACE part3_ts
);
-- 插入数据到orders_2022分区
INSERT INTO tb_order_2 PARTITION (orders_2022)
VALUES (1, 1001, TO_DATE('2022-12-31', 'YYYY-MM-DD'), 100.50, 'Pending');
-- 插入数据到orders_2023分区
INSERT INTO tb_order_2 PARTITION (orders_2023)
VALUES (1001, 2001, TO_DATE('2023-12-31', 'YYYY-MM-DD'), 200.75, 'Processing');
-- 插入数据到orders_future分区
INSERT INTO tb_order_2 PARTITION (orders_future)
VALUES (2001, 3001, TO_DATE('2024-12-31', 'YYYY-MM-DD'), 300.25, 'Completed');
-- 从orders_2022分区取数据
SELECT * FROM tb_order_2 PARTITION (orders_2022);
-- 从orders_2023分区取数据
SELECT * FROM tb_order_2 PARTITION (orders_2023);
-- 从orders_future分区取数据
SELECT * FROM tb_order_2 PARTITION (orders_future);-- todo 2 HASH分区表(散列分区表)
-- 如果分区的字段不能进行范围判断(例如名字等) 就可以使用hash分区
-- todo 2.1 创建表 tb_order_3,并使用哈希分区
CREATE TABLE tb_order_3 (order_id NUMBER PRIMARY KEY,customer_id NUMBER,order_date DATE,total_amount NUMBER(10, 2),status VARCHAR2(20)
)
PARTITION BY HASH(order_id)
(PARTITION part1 TABLESPACE part1_ts,PARTITION part2 TABLESPACE part2_ts,PARTITION part3 TABLESPACE part3_ts
);
-- 向 tb_order_3 表插入数据
INSERT INTO tb_order_3 (order_id, customer_id, order_date, total_amount, status)
VALUES (1, 1001, TO_DATE('2022-01-01', 'YYYY-MM-DD'), 100.50, 'Pending');
INSERT INTO tb_order_3 (order_id, customer_id, order_date, total_amount, status)
VALUES (2, 2001, TO_DATE('2022-01-01', 'YYYY-MM-DD'), 200.75, 'Processing');
INSERT INTO tb_order_3 (order_id, customer_id, order_date, total_amount, status)
VALUES (3, 3001, TO_DATE('2022-01-01', 'YYYY-MM-DD'), 300.25, 'Completed');
-- 验证数据插入
SELECT * FROM tb_order_3;-- todo 3 列表分区表
-- 分区字段 并非一个范围值 而是一个非连续性范围 如('北京','上海','广州', '深圳')
-- todo 3.1 创建列表分区 tb_order_4,并添加城市列作为分区键
CREATE TABLE tb_order_4 (order_id NUMBER PRIMARY KEY,customer_id NUMBER,order_date DATE,total_amount NUMBER(10, 2),status VARCHAR2(20),city VARCHAR2(50) -- 添加城市列
)
PARTITION BY LIST (city)
(PARTITION part_beijing VALUES ('北京') TABLESPACE part1_ts,PARTITION part_shanghai VALUES ('上海') TABLESPACE part2_ts,PARTITION part_guangdong VALUES ('广州', '深圳') TABLESPACE part3_ts,PARTITION qita VALUES (default) TABLESPACE part3_ts
);
-- 向 tb_order_4 表插入数据
INSERT INTO tb_order_4 (order_id, customer_id, order_date, total_amount, status, city)
VALUES (1, 1001, TO_DATE('2023-01-01', 'YYYY-MM-DD'), 100.50, 'Pending', '北京');
INSERT INTO tb_order_4 (order_id, customer_id, order_date, total_amount, status, city)
VALUES (2, 2001, TO_DATE('2023-02-01', 'YYYY-MM-DD'), 200.75, 'Processing', '上海');
INSERT INTO tb_order_4 (order_id, customer_id, order_date, total_amount, status, city)
VALUES (3, 3001, TO_DATE('2023-03-01', 'YYYY-MM-DD'), 300.25, 'Completed', '广州');
INSERT INTO tb_order_4 (order_id, customer_id, order_date, total_amount, status, city)
VALUES (4, 4001, TO_DATE('2024-03-01', 'YYYY-MM-DD'), 300.25, 'Completed', '石家庄');
-- 验证数据插入
SELECT * FROM tb_order_4;
-- 从北京分区取数据
SELECT * FROM tb_order_4 PARTITION (part_beijing);
-- 从广州分区取数据
SELECT * FROM tb_order_4 PARTITION (part_guangdong);
-- 从非一线城市取数据
SELECT * FROM tb_order_4 PARTITION (qita);-- todo 4 复合分区表(范围+哈希)(范围+列表)
-- 给表空间增加文件
ALTER TABLESPACE part1_ts ADD DATAFILE 'C:\data\part1_ts_011.dbf' SIZE 10M;
ALTER TABLESPACE part2_ts ADD DATAFILE 'C:\data\part2_ts_011.dbf' SIZE 10M;
ALTER TABLESPACE part3_ts ADD DATAFILE 'C:\data\part3_ts_011.dbf' SIZE 10M;
-- todo 4.1 创建表 tb_order_5,并使用复合分区(范围+哈希)策略
CREATE TABLE tb_order_5 (order_id NUMBER PRIMARY KEY,customer_id NUMBER,order_date DATE,total_amount NUMBER(10, 2),status VARCHAR2(20),city VARCHAR2(50)
)
PARTITION BY RANGE (order_date)
SUBPARTITION BY HASH (order_id)
SUBPARTITIONS 3
(PARTITION PART_BEFORE_2023 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD'))(SUBPARTITION part1 TABLESPACE part1_ts,SUBPARTITION part2 TABLESPACE part2_ts,SUBPARTITION part3 TABLESPACE part3_ts),PARTITION PART_2023 VALUES LESS THAN (TO_DATE('2024-01-01', 'YYYY-MM-DD'))(SUBPARTITION part4 TABLESPACE part1_ts,SUBPARTITION part5 TABLESPACE part2_ts,SUBPARTITION part6 TABLESPACE part3_ts),PARTITION PART_AFTER_2024 VALUES LESS THAN (MAXVALUE)(SUBPARTITION part7 TABLESPACE part1_ts,SUBPARTITION part8 TABLESPACE part2_ts,SUBPARTITION part9 TABLESPACE part3_ts)
);
-- 插入数据
INSERT INTO tb_order_5 (order_id, customer_id, order_date, total_amount, status, city)
VALUES (1, 1001, TO_DATE('2022-12-31', 'YYYY-MM-DD'), 100.50, 'Pending', '北京');
INSERT INTO tb_order_5 (order_id, customer_id, order_date, total_amount, status, city)
VALUES (2, 2001, TO_DATE('2023-01-01', 'YYYY-MM-DD'), 200.75, 'Processing', '上海');
-- 检索 PART_BEFORE_2023 分区中的数据
SELECT * FROM tb_order_5 PARTITION (PART_BEFORE_2023);-- 删除表空间
drop tablespace part1_ts including contents;
drop tablespace part2_ts including contents;
drop tablespace part3_ts including contents;
drop table tb_order;
drop table tb_order_2;
drop table tb_order_3;
drop table tb_order_4;
drop table tb_order_5;