Oracle——索引,序列,触发器
1.索引
1)注意
oracle创建主键时会自动在该列上创建索引
2)索引原理
A. 若没有索引,搜索某个记录时(例如查找name='wish')需要搜索所有的记录,因为不能保证只有一个wish,必须全部搜索一遍
B. 若在name上建立索引,oracle会对全表进行一次搜索,将每条记录的name值哪找升序排列,然后构建索引条目(name和rowid),存储到索引段中,查询name为wish时即可直接查找对应地方
C.创建了索引并不一定就会使用,oracle自动统计表的信息后,决定是否使用索引,表中数据很少时使用全表扫描速度已经很快,没有必要使用索引
3)索引使用()
A.创建索引的语法
CREATE [UNIQUE] | [BITMAP] INDEX index_name --unique表示唯一索引 ON table_name([column1 [ASC|DESC],column2 --bitmap,创建位图索引 [ASC|DESC],…] | [express]) [TABLESPACE tablespace_name] [PCTFREE n1] --指定索引在数据块中空闲空间 [STORAGE (INITIAL n2)] [NOLOGGING] --表示创建和重建索引时允许对表做DML操作,默认情况下不应该使用 [NOLINE] [NOSORT]; --表示创建索引时不进行排序,默认不适用,如果数据已经是按照该索引顺序排列的可以使用
B.修改索引
重命名索引:alter index index_sno rename to bitmap_sno
合并索引:表使用一段时间会产生数据碎片,此时重建索引或合并索引会很好:alter index index_sno coalesce;
重建索引:alter index index_sno rebuild;
C.删除索引
drop index index_sno
D.查看索引
create index index_sno on student('name');
select * from all_indexes where table_name='student';
4)索引分类
A:B树索引
就是我们不同的索引:create index index_sno on table('sno')
应用场景:列基数大(列不重复数)时
B:位图索引
创建位图索引时,oracle会扫描整张表,并为索引列的每个取值建立一个位图(位图中,对表中每一行使用一位(bit,0或者1)来标识该行是否包含该位图的索引列的取值,如果为1,表示对应的rowid所在的记录包含该位图索引列值),最后通过位图索引中的映射函数完成位到行的ROWID的转换
create bitmap index index_sno on table(sno);
应用场景:基数小的列
C:单列索引复合索引
D:函数索引
create index fbi on student (upper(name));
select * from student where upper(name) ='WISH';
5)原则
1. 如果有两个或者以上的索引,其中有一个唯一性索引,而其他是非唯一,这种情况下oracle将使用唯一性索引而完全忽略非唯一性索引
2. 至少要包含组合索引的第一列(即如果索引建立在多个列上,只有它的第一个列被where子句引用时,优化器才会使用该索引)
3. 小表不要简历索引
4. 对于基数大的列适合建立B树索引,对于基数小的列适合简历位图索引
5. 列中有很多空值,但经常查询该列上非空记录时应该建立索引
6. 经常进行连接查询的列应该创建索引
7. 使用create index时要将最常查询的列放在最前面
8. LONG(可变长字符串数据,最长2G)和LONG RAW(可变长二进制数据,最长2G)列不能创建索引
9.限制表中索引的数量(创建索引耗费时间,并且随数据量的增大而增大;索引会占用物理空间;当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度)
6)注意事项
1. 通配符在搜索词首出现时,oracle不能使用索引,eg:
--我们在name上创建索引; create index index_name on student('name'); --下面的方式oracle不适用name索引 select * from student where name like '%wish%'; --如果通配符出现在字符串的其他位置时,优化器能够利用索引;如下: select * from student where name like 'wish%';
2. 不要在索引列上使用not,可以采用其他方式代替如下:(oracle碰到not会停止使用索引,而采用全表扫描)
select * from student where not (score=100); select * from student where score <> 100; --替换为 select * from student where score>100 or score <100
3. 索引上使用空值比较将停止使用索引, eg:
select * from student where score is not null;
2.序列
1)创建序列
2)通过序列插入表数据自增长
insert into textseq values(seq_textseq.nextval,'zs')
3.同义词
Create synonym dept for scott.dept;创建私有同义词
drop synonym dept;删除私有同义词
Create public synonym dept for scott.dept;创建共有同义词
drop public sysnonym dept;删除共有同义词
3.触发器
http://blog.csdn.net/indexman/article/details/8023740/
1)创建触发器的一般语法
CREATE [OR REPLACE] TRIGGER trigger_name {BEFORE | AFTER } {INSERT | DELETE | UPDATE [OF column [, column …]]} [OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...] ON [schema.]table_name | [schema.]view_name [REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}] [FOR EACH ROW ] [WHEN condition] PL/SQL_BLOCK | CALL procedure_name;
BEFORE 和AFTER指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。
FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操作影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则只能为行触发器。
REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。
WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。
当一个基表被修改( INSERT, UPDATE, DELETE)时要执行的存储过程,执行时根据其所依附的基表改动而自动触发,因此与应用程序无关,用数据库触发器可以保证数据的一致性和完整性。
2)例子:建立一个触发器, 当职工表 emp 表被删除一条记录时,把被删除记录写到职工表删除日志表中去。
CREATE TABLE emp_his AS SELECT * FROM EMP WHERE 1=2; CREATE OR REPLACE TRIGGER tr_del_emp BEFORE DELETE --指定触发时机为删除操作前触发 ON scott.emp FOR EACH ROW --说明创建的是行级触发器 BEGIN --将修改前数据插入到日志记录表 del_emp ,以供监督使用。 INSERT INTO emp_his(deptno , empno, ename , job ,mgr , sal , comm , hiredate ) VALUES( :old.deptno, :old.empno, :old.ename , :old.job,:old.mgr, :old.sal, :old.comm, :old.hiredate ); END; DELETE emp WHERE empno=7788; DROP TABLE emp_his; DROP TRIGGER del_emp;
限制对Departments表修改(包括INSERT,DELETE,UPDATE)的时间范围,即不允许在非工作时间修改departments表
CREATE OR REPLACE TRIGGER tr_dept_time BEFORE INSERT OR DELETE OR UPDATE ON departments BEGIN IF (TO_CHAR(sysdate,'DAY') IN ('星期六', '星期日')) OR (TO_CHAR(sysdate, 'HH24:MI') NOT BETWEEN '08:30' AND '18:00') THEN RAISE_APPLICATION_ERROR(-20001, '不是上班时间,不能修改departments表'); END IF; END;