目 录
1.选用适合的ORACLE优化器 2
2.访问Table的方式 3
3.共享SQL语句 3
4.选择最有效率的表名顺序(只在基于规则的优化器中有效) 5
5.WHERE子句中的连接顺序. 6
6.SELECT子句中避免使用 ‘ * ‘ 7
7.减少访问数据库的次数 7
8.使用DECODE函数来减少处理时间 8
9.整合简单,无关联的数据库访问 9
10.删除重复记录 10
11.用TRUNCATE替代DELETE 10
12.尽量多使用COMMIT 11
13.计算记录条数 11
14.用Where子句替换HAVING子句 11
15.减少对表的查询 12
16.通过内部函数提高SQL效率. 13
17.使用表的别名(Alias) 15
18.用EXISTS替代IN 15
19.用NOT EXISTS替代NOT IN 16
20.用表连接替换EXISTS 17
21.用EXISTS替换DISTINCT 17
22.识别’低效执行’的SQL语句 18
23.使用TKPROF 工具来查询SQL性能状态 19
24.用EXPLAIN PLAN 分析SQL语句 19
25.用索引提高效率 21
26.索引的操作 21
27.基础表的选择 23
28.多个平等的索引 23
29. 等式比较和范围比较 24
30.不明确的索引等级 25
31.强制索引失效 26
32.避免在索引列上使用计算. 27
33.自动选择索引 27
34.避免在索引列上使用NOT 28
35.用>=替代> 29
36.用UNION替换OR (适用于索引列) 30
37.用IN来替换OR 34
38.避免在索引列上使用IS NULL和IS NOT NULL 34
39.总是使用索引的第一个列 35
40.ORACLE内部操作 36
41.用UNION-ALL 替换UNION ( 如果有可能的话) 37
42.使用提示(Hints) 38
43.用WHERE替代ORDER BY 39
44.避免改变索引列的类型. 40
45.需要当心的WHERE子句 41
46.连接多个扫描 43
47.CBO下使用更具选择性的索引 44
48.避免使用耗费资源的操作 44
49.优化GROUP BY 45
50.使用日期 46
51.使用显式的游标(CURSORs) 46
52. 优化EXPORT和IMPORT 46
53. 分离表和索引 47

1.选用适合的ORACLE优化器
ORACLE的优化器共有3种:
a. RULE (基于规则) b. COST (基于成本) c. CHOOSE (选择性)
设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖.
为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须经常运行analyze 命令,以增加数据库中的对象统计信息(object statistics)的准确性.
如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器.
在缺省情况下,ORACLE采用CHOOSE优化器, 为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器.
2.访问Table的方式
ORACLE 采用两种访问表中记录的方式:
a.全表扫描
全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描.
b.通过ROWID访问表
你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息…ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.
3.共享SQL语句
为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用.
可惜的是ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询.
数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句,当然被共享的可能性也就越大了.
当你向ORACLE 提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句.这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全相同(包括空格,换行等).
共享的语句必须满足三个条件:
A.字符级的比较:
当前被执行的语句和共享池中的语句必须完全相同.
例如:
SELECT * FROM EMP;
和下列每一个都不同
SELECT * from EMP;
Select * From Emp;
SELECT * FROM EMP;
B.两个语句所指的对象必须完全相同:
例如:
用户 对象名 如何访问
Jack sal_limit private synonym
Work_city public synonym
Plant_detail public synonym
Jill sal_limit private synonym
Work_city public synonym
Plant_detail table owner
考虑一下下列SQL语句能否在这两个用户之间共享.
SQL 能否共享 原因
select max(sal_cap) from sal_limit; 不能 每个用户都有一个private synonym - sal_limit , 它们是不同的对象
select count() from work_city where sdesc like ‘NEW%’; 能 两个用户访问相同的对象public synonym - work_city
select a.sdesc,b.location from work_city a , plant_detail b where a.city_id = b.city_id 不能 用户jack 通过private synonym访问plant_detail 而jill 是表的所有者,对象不同.
C. 两个SQL语句中必须使用相同的名字的绑定变量(bind variables)
例如:
第一组的两个SQL语句是相同的(可以共享),而第二组中的两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值)
a.
select pin , name from people where pin = :blk1.pin;
select pin , name from people where pin = :blk1.pin;
b.
select pin , name from people where pin = :blk1.ot_ind;
select pin , name from people where pin = :blk1.ov_ind;
4.选择最有效率的表名顺序(只在基于规则的优化器中有效)
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并.
例如:
表 TAB1 16,384 条记录
表 TAB2 1 条记录
选择TAB2作为基础表 (最好的方法)
select count(
) from tab1,tab2 执行时间0.96秒
选择TAB2作为基础表 (不佳的方法)
select count() from tab2,tab1 执行时间26.09秒
如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.
例如:
EMP表描述了LOCATION表和CATEGORY表的交集.
SELECT *
FROM LOCATION L ,
CATEGORY C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
将比下列SQL更有效率
SELECT *
FROM EMP E ,
LOCATION L ,
CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
5.WHERE子句中的连接顺序.
ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.
例如:
(低效,执行时间156.3秒)
SELECT …
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER’
AND 25 < (SELECT COUNT(
) FROM EMP
WHERE MGR=E.EMPNO);
(高效,执行时间10.6秒)
SELECT …
FROM EMP E
WHERE 25 < (SELECT COUNT() FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER’;
6.SELECT子句中避免使用 ‘ * ‘
当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 ‘
’ 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将’’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.
7.减少访问数据库的次数
当执行每条SQL语句时, ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等等. 由此可见, 减少访问数据库的次数 , 就能实际上减少ORACLE的工作量.
例如,以下有三种方法可以检索出雇员号等于0342或0291的职员.
方法1 (最低效)
SELECT EMP_NAME , SALARY , GRADE
FROM EMP
WHERE EMP_NO = 342;
SELECT EMP_NAME , SALARY , GRADE
FROM EMP
WHERE EMP_NO = 291;
方法2 (次低效)
DECLARE
CURSOR C1 (E_NO NUMBER) IS
SELECT EMP_NAME,SALARY,GRADE
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH C1 INTO …,…,… ;
……
OPEN C1(291);
FETCH C1 INTO …,…,… ;
CLOSE C1;
END;
方法3 (高效)
SELECT A.EMP_NAME , A.SALARY , A.GRADE,
B.EMP_NAME , B.SALARY , B.GRADE
FROM EMP A,EMP B
WHERE A.EMP_NO = 342
AND B.EMP_NO = 291;
注意:
在SQL
Plus , SQLForms和ProC中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200
8.使用DECODE函数来减少处理时间
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.
例如:
SELECT COUNT(),SUM(SAL)
FROM EMP
WHERE DEPT_NO = 0020
AND ENAME LIKE ‘SMITH%’;
SELECT COUNT(
),SUM(SAL)
FROM EMP
WHERE DEPT_NO = 0030
AND ENAME LIKE ‘SMITH%’;
你可以用DECODE函数高效地得到相同结果
SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE ‘SMITH%’;
类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.
9.整合简单,无关联的数据库访问
如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)
例如:
SELECT NAME
FROM EMP
WHERE EMP_NO = 1234;
SELECT NAME
FROM DPT
WHERE DPT_NO = 10 ;
SELECT NAME
FROM CAT
WHERE CAT_TYPE = ‘RD’;
上面的3个查询可以被合并成一个:
SELECT E.NAME , D.NAME , C.NAME
FROM CAT C , DPT D , EMP E,DUAL X
WHERE NVL(‘X’,X.DUMMY) = NVL(‘X’,E.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,D.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,C.ROWID(+))
AND E.EMP_NO(+) = 1234
AND D.DEPT_NO(+) = 10
AND C.CAT_TYPE(+) = ‘RD’;
(译者按: 虽然采取这种方法,效率得到提高,但是程序的可读性大大降低,所以读者 还是要权衡之间的利弊)
10.删除重复记录
最高效的删除重复记录方法 ( 因为使用了ROWID)
DELETE FROM EMP E
WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X
WHERE X.EMP_NO = E.EMP_NO);
11.用TRUNCATE替代DELETE
当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况)
而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短.
(译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML)
12.尽量多使用COMMIT
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少:
COMMIT所释放的资源:
a. 回滚段上用于恢复数据的信息.
b. 被程序语句获得的锁
c. redo log buffer 中的空间
d. ORACLE为管理上述3种资源中的内部花费
(译者按: 在使用COMMIT时必须要注意到事务的完整性,现实中效率和事务完整性往往是鱼和熊掌不可得兼)
13.计算记录条数
和一般的观点相反, count() 比count(1)稍快 , 当然如果可以通过索引检索,对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO)
(译者按: 在CSDN论坛中,曾经对此有过相当热烈的讨论, 作者的观点并不十分准确,通过实际的测试,上述三种方法并没有显著的性能差别)
14.用Where子句替换HAVING子句
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.
例如:
低效:
SELECT REGION,AVG(LOG_SIZE)
FROM LOCATION
GROUP BY REGION
HAVING REGION REGION != ‘SYDNEY’
AND REGION != ‘PERTH’
高效
SELECT REGION,AVG(LOG_SIZE)
FROM LOCATION
WHERE REGION REGION != ‘SYDNEY’
AND REGION != ‘PERTH’
GROUP BY REGION
(译者按: HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中)
15.减少对表的查询
在含有子查询的SQL语句中,要特别注意减少对表的查询.
例如:
低效
SELECT TAB_NAME
FROM TABLES
WHERE TAB_NAME = ( SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION = 604)
AND DB_VER= ( SELECT DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
高效
SELECT TAB_NAME
FROM TABLES
WHERE (TAB_NAME,DB_VER)
= ( SELECT TAB_NAME,DB_VER)
FROM TAB_COLUMNS
WHERE VERSION = 604)
Update 多个Column 例子:
低效:
UPDATE EMP
SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES),
SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;
高效:
UPDATE EMP
SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)
FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;
16.通过内部函数提高SQL效率.
SELECT H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC,COUNT(
)
FROM HISTORY_TYPE T,EMP E,EMP_HISTORY H
WHERE H.EMPNO = E.EMPNO
AND H.HIST_TYPE = T.HIST_TYPE
GROUP BY H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC;
通过调用下面的函数可以提高效率.
FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN VARCHAR2
AS
TDESC VARCHAR2(30);
CURSOR C1 IS
SELECT TYPE_DESC
FROM HISTORY_TYPE
WHERE HIST_TYPE = TYP;
BEGIN
OPEN C1;
FETCH C1 INTO TDESC;
CLOSE C1;
RETURN (NVL(TDESC,’?’));
END;
FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN VARCHAR2
AS
ENAME VARCHAR2(30);
CURSOR C1 IS
SELECT ENAME
FROM EMP
WHERE EMPNO=EMP;
BEGIN
OPEN C1;
FETCH C1 INTO ENAME;
CLOSE C1;
RETURN (NVL(ENAME,’?’));
END;
SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO),
H.HIST_TYPE,LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT()
FROM EMP_HISTORY H
GROUP BY H.EMPNO , H.HIST_TYPE;
(译者按: 经常在论坛中看到如 ’能不能用一个SQL写出….’ 的贴子, 殊不知复杂的SQL往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的)
17.使用表的别名(Alias)
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
(译者注: Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属)
18.用EXISTS替代IN
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
低效:
SELECT *
FROM EMP (基础表)
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC = ‘MELB’)
高效:
SELECT *
FROM EMP (基础表)
WHERE EMPNO > 0
AND EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ‘MELB’)
(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出)
19.用NOT EXISTS替代NOT IN
在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
例如:
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO
FROM DEPT
WHERE DEPT_CAT=’A’);
为了提高效率.改写为:
(方法一: 高效)
SELECT ….
FROM EMP A,DEPT B
WHERE A.DEPT_NO = B.DEPT(+)
AND B.DEPT_NO IS NULL
AND B.DEPT_CAT(+) = ‘A’
(方法二: 最高效)
SELECT ….
FROM EMP E
WHERE NOT EXISTS (SELECT ‘X’
FROM DEPT D
WHERE D.DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A’);
20.用表连接替换EXISTS
通常来说 , 采用表连接的方式比EXISTS更有效率
SELECT ENAME
FROM EMP E
WHERE EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A’);
(更高效)
SELECT ENAME
FROM DEPT D,EMP E
WHERE E.DEPT_NO = D.DEPT_NO
AND DEPT_CAT = ‘A’ ;
(译者按: 在RBO的情况下,前者的执行路径包括FILTER,后者使用NESTED LOOP)
21.用EXISTS替换DISTINCT
当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换
例如:
低效:
SELECT DISTINCT DEPT_NO,DEPT_NAME
FROM DEPT D,EMP E
WHERE D.DEPT_NO = E.DEPT_NO
高效:
SELECT DEPT_NO,DEPT_NAME
FROM DEPT D
WHERE EXISTS ( SELECT ‘X’
FROM EMP E
WHERE E.DEPT_NO = D.DEPT_NO);
EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.
22.识别’低效执行’的SQL语句
用下列SQL工具找出低效SQL:
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;
(译者按: 虽然目前各种关于SQL优化的图形化工具层出不穷,但是写出自己的SQL工具来解决问题始终是一个最好的方法)
23.使用TKPROF 工具来查询SQL性能状态
SQL trace 工具收集正在执行的SQL的性能状态数据并记录到一个跟踪文件中. 这个跟踪文件提供了许多有用的信息,例如解析次数.执行次数,CPU使用时间等.这些数据将可以用来优化你的系统.
设置SQL TRACE在会话级别: 有效
ALTER SESSION SET SQL_TRACE TRUE
设置SQL TRACE 在整个数据库有效仿, 你必须将SQL_TRACE参数在init.ora中设为TRUE, USER_DUMP_DEST参数说明了生成跟踪文件的目录
(译者按: 这一节中,作者并没有提到TKPROF的用法, 对SQL TRACE的用法也不够准确, 设置SQL TRACE首先要在init.ora中设定TIMED_STATISTICS, 这样才能得到那些重要的时间状态. 生成的trace文件是不可读的,所以要用TKPROF工具对其进行转换,TKPROF有许多执行参数. 大家可以参考ORACLE手册来了解具体的配置. )
24.用EXPLAIN PLAN 分析SQL语句
EXPLAIN PLAN 是一个很好的分析SQL语句的工具,它甚至可以在不执行SQL的情况下分析语句. 通过分析,我们就可以知道ORACLE是怎么样连接表,使用什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称.
你需要按照从里到外,从上到下的次序解读分析的结果. EXPLAIN PLAN分析的结果是用缩进的格式排列的, 最内部的操作将被最先解读, 如果两个操作处于同一层中,带有最小操作号的将被首先执行.
NESTED LOOP是少数不按照上述规则处理的操作, 正确的执行路径是检查对NESTED LOOP提供数据的操作,其中操作号最小的将被最先处理.
译者按: 通过实践, 感到还是用SQLPLUS中的SET TRACE 功能比较方便.举例:
SQL> list
1 SELECT *
2 FROM dept, emp
3
WHERE emp.deptno = dept.deptno
SQL> set autotrace traceonly /traceonly 可以不显示执行结果/
SQL> /
14 rows selected.
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF ‘EMP’
3 1 TABLE ACCESS (BY INDEX ROWID) OF ‘DEPT’
4 3 INDEX (UNIQUE SCAN) OF ‘PK_DEPT’ (UNIQUE)
Statistics

      0  recursive calls2  db block gets30  consistent gets0  physical reads0  redo size2598  bytes sent via SQL*Net to client503  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)14  rows processed

通过以上分析,可以得出实际的执行步骤是:

  1.   TABLE ACCESS (FULL) OF 'EMP'
    
  2.   INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)
    
  3.   TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
    
  4.   NESTED LOOPS (JOINING 1 AND 3)
    

注: 目前许多第三方的工具如TOAD和ORACLE本身提供的工具如OMS的SQL Analyze都提供了极其方便的EXPLAIN PLAN工具.也许喜欢图形化界面的朋友们可以选用它们.
25.用索引提高效率
索引是表的一个概念部分,用来提高检索数据的效率. 实际上,ORACLE使用了一个复杂的自平衡B-tree结构. 通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率. 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证.
除了那些LONG或LONG RAW数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现, 在扫描小表时,使用索引同样能提高效率.
虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT ,DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.
译者按: 定期的重构索引是有必要的. ALTER INDEX REBUILD
26.索引的操作
ORACLE对索引有两种访问模式.
索引唯一扫描 ( INDEX UNIQUE SCAN)
大多数情况下, 优化器通过WHERE子句访问INDEX.
例如:
表LODGING有两个索引 : 建立在LODGING列上的唯一性索引LODGING_PK和建立在MANAGER列上的非唯一性索引LODGING$MANAGER.
SELECT *
FROM LODGING
WHERE LODGING = ‘ROSE HILL’;
在内部 , 上述SQL将被分成两步执行, 首先 , LODGING_PK 索引将通过索引唯一扫描的方式被访问 , 获得相对应的ROWID, 通过ROWID访问表的方式 执行下一步检索.
如果被检索返回的列包括在INDEX列中,ORACLE将不执行第二步的处理(通过ROWID访问表). 因为检索数据保存在索引中, 单单访问索引就可以完全满足查询结果.
下面SQL只需要INDEX UNIQUE SCAN 操作.
SELECT LODGING
FROM LODGING
WHERE LODGING = ‘ROSE HILL’;
索引范围查询(INDEX RANGE SCAN)
适用于两种情况:

  1.   基于一个范围的检索
    
  2.   基于非唯一性索引的检索
    

例1:
SELECT LODGING
FROM LODGING
WHERE LODGING LIKE ‘M%’;
WHERE子句条件包括一系列值, ORACLE将通过索引范围查询的方式查询LODGING_PK . 由于索引范围查询将返回一组值, 它的效率就要比索引唯一扫描低一些.
例2:
SELECT LODGING
FROM LODGING
WHERE MANAGER = ‘BILL GATES’;
这个SQL的执行分两步, LODGINGMANAGER的索引范围查询(得到所有符合条件记录的ROWID)和下一步同过ROWID访问表得到LODGING列的值.由于LODGINGMANAGER的索引范围查询(得到所有符合条件记录的ROWID) 和下一步同过ROWID访问表得到LODGING列的值. 由于LODGINGMANAGER的索引范围查询(得到所有符合条件记录的ROWID)和下一步同过ROWID访问表得到LODGING列的值.由于LODGINGMANAGER是一个非唯一性的索引,数据库不能对它执行索引唯一扫描.
由于SQL返回LODGING列,而它并不存在于LODGING$MANAGER索引中, 所以在索引范围查询后会执行一个通过ROWID访问表的操作.
WHERE子句中, 如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始, 索引将不被采用.
SELECT LODGING
FROM LODGING
WHERE MANAGER LIKE ‘%HANMAN’;
在这种情况下,ORACLE将使用全表扫描.
27.基础表的选择
基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问). 根据优化器的不同, SQL语句中基础表的选择是不一样的.
如果你使用的是CBO (COST BASED OPTIMIZER),优化器会检查SQL语句中的每个表的物理大小,索引的状态,然后选用花费最低的执行路径.
如果你用RBO (RULE BASED OPTIMIZER) , 并且所有的连接条件都有索引对应, 在这种情况下, 基础表就是FROM 子句中列在最后的那个表.
举例:
SELECT A.NAME , B.MANAGER
FROM WORKER A,
LODGING B
WHERE A.LODGING = B.LODING;
由于LODGING表的LODING列上有一个索引, 而且WORKER表中没有相比较的索引, WORKER表将被作为查询中的基础表.
28.多个平等的索引
当SQL语句的执行路径可以使用分布在多个表上的多个索引时, ORACLE会同时使用多个索引并在运行时对它们的记录进行合并, 检索出仅对全部索引有效的记录.
在ORACLE选择执行路径时,唯一性索引的等级高于非唯一性索引. 然而这个规则只有当WHERE子句中索引列和常量比较才有效.如果索引列和其他表的索引类相比较. 这种子句在优化器中的等级是非常低的.
如果不同表中两个想同等级的索引将被引用, FROM子句中表的顺序将决定哪个会被率先使用. FROM子句中最后的表的索引将有最高的优先级.
如果相同表中两个想同等级的索引将被引用, WHERE子句中最先被引用的索引将有最高的优先级.
举例:
DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引.
SELECT ENAME,
FROM EMP
WHERE DEPT_NO = 20
AND EMP_CAT = ‘A’;
这里,DEPTNO索引将被最先检索,然后同EMP_CAT索引检索出的记录进行合并. 执行路径如下:

TABLE ACCESS BY ROWID ON EMP
AND-EQUAL
INDEX RANGE SCAN ON DEPT_IDX
INDEX RANGE SCAN ON CAT_IDX
29. 等式比较和范围比较
当WHERE子句中有索引列, ORACLE不能合并它们,ORACLE将用范围比较.
举例:
DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引.
SELECT ENAME
FROM EMP
WHERE DEPTNO > 20
AND EMP_CAT = ‘A’;
这里只有EMP_CAT索引被用到,然后所有的记录将逐条与DEPTNO条件进行比较. 执行路径如下:
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON CAT_IDX
30.不明确的索引等级
当ORACLE无法判断索引的等级高低差别,优化器将只使用一个索引,它就是在WHERE子句中被列在最前面的.举例:
DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引.
SELECT ENAME
FROM EMP
WHERE DEPTNO > 20
AND EMP_CAT > ‘A’;
这里, ORACLE只用到了DEPT_NO索引. 执行路径如下:

 TABLE ACCESS BY ROWID ON EMPINDEX RANGE SCAN ON DEPT_IDX

译者按:
我们来试一下以下这种情况:
SQL> select index_name, uniqueness from user_indexes where table_name = ‘EMP’;
INDEX_NAME UNIQUENES


EMPNO UNIQUE
EMPTYPE NONUNIQUE
SQL> select * from emp where empno >= 2 and emp_type = ‘A’ ;
no rows selected
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’
2 1 INDEX (RANGE SCAN) OF ‘EMPTYPE’ (NON-UNIQUE)
虽然EMPNO是唯一性索引,但是由于它所做的是范围比较, 等级要比非唯一性索引的等式比较低!
31.强制索引失效
如果两个或以上索引具有相同的等级,你可以强制命令ORACLE优化器使用其中的一个(通过它,检索出的记录数量少) .
举例:

SELECT ENAME
FROM EMP
WHERE EMPNO = 7935
AND DEPTNO + 0 = 10 /DEPTNO上的索引将失效/
AND EMP_TYPE || ‘’ = ‘A’ /EMP_TYPE上的索引将失效/
这是一种相当直接的提高查询效率的办法. 但是你必须谨慎考虑这种策略,一般来说,只有在你希望单独优化几个SQL时才能采用它.
这里有一个例子关于何时采用这种策略,
假设在EMP表的EMP_TYPE列上有一个非唯一性的索引而EMP_CLASS上没有索引.
SELECT ENAME
FROM EMP
WHERE EMP_TYPE = ‘A’
AND EMP_CLASS = ‘X’;
优化器会注意到EMP_TYPE上的索引并使用它. 这是目前唯一的选择. 如果,一段时间以后, 另一个非唯一性建立在EMP_CLASS上,优化器必须对两个索引进行选择,在通常情况下,优化器将使用两个索引并在他们的结果集合上执行排序及合并. 然而,如果其中一个索引(EMP_TYPE)接近于唯一性而另一个索引(EMP_CLASS)上有几千个重复的值. 排序及合并就会成为一种不必要的负担. 在这种情况下,你希望使优化器屏蔽掉EMP_CLASS索引.
用下面的方案就可以解决问题.
SELECT ENAME
FROM EMP
WHERE EMP_TYPE = ‘A’
AND EMP_CLASS||’’ = ‘X’;
32.避免在索引列上使用计算.
WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.
举例:
低效:
SELECT …
FROM DEPT
WHERE SAL * 12 > 25000;
高效:
SELECT …
FROM DEPT
WHERE SAL > 25000/12;
译者按:这是一个非常实用的规则,请务必牢记
33.自动选择索引
如果表中有两个以上(包括两个)索引,其中有一个唯一性索引,而其他是非唯一性.
在这种情况下,ORACLE将使用唯一性索引而完全忽略非唯一性索引.
举例:
SELECT ENAME
FROM EMP
WHERE EMPNO = 2326
AND DEPTNO = 20 ;
这里,只有EMPNO上的索引是唯一性的,所以EMPNO索引将用来检索记录.
TABLE ACCESS BY ROWID ON EMP
INDEX UNIQUE SCAN ON EMP_NO_IDX
34.避免在索引列上使用NOT
通常,我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描.
举例:
低效: (这里,不使用索引)
SELECT …
FROM DEPT
WHERE DEPT_CODE NOT = 0;
高效: (这里,使用了索引)
SELECT …
FROM DEPT
WHERE DEPT_CODE > 0;
需要注意的是,在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符.
NOT > to <=
NOT >= to <
NOT < to >=
NOT <= to >
译者按:
在这个例子中,作者犯了一些错误. 例子中的低效率SQL是不能被执行的.
我做了一些测试:
SQL> select * from emp where NOT empno > 1;
no rows selected
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’
2 1 INDEX (RANGE SCAN) OF ‘EMPNO’ (UNIQUE)
SQL> select * from emp where empno <= 1;
no rows selected
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’
2 1 INDEX (RANGE SCAN) OF ‘EMPNO’ (UNIQUE)
两者的效率完全一样,也许这符合作者关于” 在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符” 的观点.
35.用>=替代>
如果DEPTNO上有一个索引,
高效:
SELECT *
FROM EMP
WHERE DEPTNO >=4
低效:
SELECT *
FROM EMP
WHERE DEPTNO >3
两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录.
36.用UNION替换OR (适用于索引列)
通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果.对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低.
在下面的例子中, LOC_ID 和REGION上都建有索引.
高效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面.
注意:
WHERE KEY1 = 10 (返回最少记录)
OR KEY2 = 20 (返回最多记录)
ORACLE 内部将以上转换为
WHERE KEY1 = 10 AND
((NOT KEY1 = 10) AND KEY2 = 20)
译者按:
下面的测试数据仅供参考: (a = 1003 返回一条记录 , b = 1 返回1003条记录)
SQL> select * from unionvsor /1st test/
2 where a = 1003 or b = 1;
1003 rows selected.
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 CONCATENATION
2 1 TABLE ACCESS (BY INDEX ROWID) OF ‘UNIONVSOR’
3 2 INDEX (RANGE SCAN) OF ‘UB’ (NON-UNIQUE)
4 1 TABLE ACCESS (BY INDEX ROWID) OF ‘UNIONVSOR’
5 4 INDEX (RANGE SCAN) OF ‘UA’ (NON-UNIQUE)
Statistics

      0  recursive calls0  db block gets144  consistent gets0  physical reads0  redo size63749  bytes sent via SQL*Net to client7751  bytes received via SQL*Net from client68  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1003  rows processed

SQL> select * from unionvsor /2nd test/
2 where b = 1 or a = 1003 ;
1003 rows selected.
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 CONCATENATION
2 1 TABLE ACCESS (BY INDEX ROWID) OF ‘UNIONVSOR’
3 2 INDEX (RANGE SCAN) OF ‘UA’ (NON-UNIQUE)
4 1 TABLE ACCESS (BY INDEX ROWID) OF ‘UNIONVSOR’
5 4 INDEX (RANGE SCAN) OF ‘UB’ (NON-UNIQUE)
Statistics

      0  recursive calls0  db block gets143  consistent gets0  physical reads0  redo size63749  bytes sent via SQL*Net to client7751  bytes received via SQL*Net from client68  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1003  rows processed

SQL> select * from unionvsor /3rd test/
2 where a = 1003
3 union
4 select * from unionvsor
5 where b = 1;
1003 rows selected.
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (UNIQUE)
2 1 UNION-ALL
3 2 TABLE ACCESS (BY INDEX ROWID) OF ‘UNIONVSOR’
4 3 INDEX (RANGE SCAN) OF ‘UA’ (NON-UNIQUE)
5 2 TABLE ACCESS (BY INDEX ROWID) OF ‘UNIONVSOR’
6 5 INDEX (RANGE SCAN) OF ‘UB’ (NON-UNIQUE)
Statistics

      0  recursive calls0  db block gets10  consistent gets   0  physical reads0  redo size63735  bytes sent via SQL*Net to client7751  bytes received via SQL*Net from client68  SQL*Net roundtrips to/from client1  sorts (memory)0  sorts (disk)1003  rows processed

用UNION的效果可以从consistent gets和 SQL*NET的数据交换量的减少看出
37.用IN来替换OR
下面的查询可以被更有效率的语句替换:
低效:
SELECT….
FROM LOCATION
WHERE LOC_ID = 10
OR LOC_ID = 20
OR LOC_ID = 30
高效
SELECT…
FROM LOCATION
WHERE LOC_IN IN (10,20,30);
译者按:
这是一条简单易记的规则,但是实际的执行效果还须检验,在ORACLE8i下,两者的执行路径似乎是相同的. 
38.避免在索引列上使用IS NULL和IS NOT NULL
避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引 .对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.
举例:
如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B值为(123,null) , ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空. 因此你可以插入1000条具有相同键值的记录,当然它们都是空!
因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引.
举例:
低效: (索引失效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE >=0;
39.总是使用索引的第一个列
如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引.
译者按:
这也是一条简单而重要的规则. 见以下实例.
SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10));
Table created.
SQL> create index multindex on multiindexusage(inda,indb);
Index created.
SQL> set autotrace traceonly
SQL> select * from multiindexusage where inda = 1;
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘MULTIINDEXUSAGE’
2 1 INDEX (RANGE SCAN) OF ‘MULTINDEX’ (NON-UNIQUE)
SQL> select * from multiindexusage where indb = 1;
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF ‘MULTIINDEXUSAGE’
很明显, 当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引
40.ORACLE内部操作
当执行查询时,ORACLE采用了内部的操作. 下表显示了几种重要的内部操作.
ORACLE Clause 内部操作
ORDER BY SORT ORDER BY
UNION UNION-ALL
MINUS MINUS
INTERSECT INTERSECT
DISTINCT,MINUS,INTERSECT,UNION SORT UNIQUE
MIN,MAX,COUNT SORT AGGREGATE
GROUP BY SORT GROUP BY
ROWNUM COUNT or COUNT STOPKEY
Queries involving Joins SORT JOIN,MERGE JOIN,NESTED LOOPS
CONNECT BY CONNECT BY

41.用UNION-ALL 替换UNION ( 如果有可能的话)
当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序.
如果用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会因此得到提高.
举例:
低效:
    SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = ’31-DEC-95’
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = ’31-DEC-95’
高效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = ’31-DEC-95’
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = ’31-DEC-95’
译者按:
需要注意的是,UNION ALL 将重复输出两个结果集合中相同记录. 因此各位还是要从业务需求分析使用UNION ALL的可行性.
UNION 将对结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存. 对于这块内存的优化也是相当重要的. 下面的SQL可以用来查询排序的消耗量
Select substr(name,1,25) “Sort Area Name”, substr(value,1,15) “Value”
from v$sysstat
where name like ‘sort%’
42.使用提示(Hints)
对于表的访问,可以使用两种Hints.
FULL 和 ROWID
FULL hint 告诉ORACLE使用全表扫描的方式访问指定表.
例如:
SELECT /+ FULL(EMP) / *
FROM EMP
WHERE EMPNO = 7893;
ROWID hint 告诉ORACLE使用TABLE ACCESS BY ROWID的操作访问表.
通常, 你需要采用TABLE ACCESS BY ROWID的方式特别是当访问大表的时候, 使用这种方式, 你需要知道ROIWD的值或者使用索引.
如果一个大表没有被设定为缓存(CACHED)表而你希望它的数据在查询结束是仍然停留在SGA中,你就可以使用CACHE hint 来告诉优化器把数据保留在SGA中. 通常CACHE hint 和 FULL hint 一起使用.
例如:
SELECT /
+ FULL(WORKER) CACHE(WORKER)
/ *
FROM WORK;
索引hint 告诉ORACLE使用基于索引的扫描方式. 你不必说明具体的索引名称
例如:
SELECT /*+ INDEX(LODGING) */ LODGING
FROM LODGING
WHERE MANAGER = ‘BILL GATES’;
在不使用hint的情况下, 以上的查询应该也会使用索引,然而,如果该索引的重复值过多而你的优化器是CBO, 优化器就可能忽略索引. 在这种情况下, 你可以用INDEX hint强制ORACLE使用该索引.
ORACLE hints 还包括ALL_ROWS, FIRST_ROWS, RULE,USE_NL, USE_MERGE, USE_HASH 等等.
译者按:
使用hint , 表示我们对ORACLE优化器缺省的执行路径不满意,需要手工修改.这是一个很有技巧性的工作. 我建议只针对特定的,少数的SQL进行hint的优化.对ORACLE的优化器还是要有信心(特别是CBO)
43.用WHERE替代ORDER BY
ORDER BY 子句只在两种严格的条件下使用索引.
ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.
ORDER BY中所有的列必须定义为非空.
WHERE子句使用的索引和ORDER BY子句中所使用的索引不能并列.
例如:
表DEPT包含以下列:
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
非唯一性的索引(DEPT_TYPE)
低效: (索引不被使用)
SELECT DEPT_CODE
FROM DEPT
ORDER BY DEPT_TYPE
EXPLAIN PLAN:
SORT ORDER BY
TABLE ACCESS FULL
高效: (使用索引)
SELECT DEPT_CODE
FROM DEPT
WHERE DEPT_TYPE > 0
EXPLAIN PLAN:
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON DEPT_IDX
译者按:
ORDER BY 也能使用索引! 这的确是个容易被忽视的知识点. 我们来验证一下:
SQL> select * from emp order by empno;
Execution Plan

0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’
2 1 INDEX (FULL SCAN) OF ‘EMPNO’ (UNIQUE)
44.避免改变索引列的类型.
当比较不同数据类型的数据时, ORACLE自动对列进行简单的类型转换.
假设 EMPNO是一个数值类型的索引列.
SELECT …
FROM EMP
WHERE EMPNO = ‘123’
实际上,经过ORACLE类型转换, 语句转化为:
SELECT …
FROM EMP
WHERE EMPNO = TO_NUMBER(‘123’)
幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.
现在,假设EMP_TYPE是一个字符类型的索引列.
SELECT …
FROM EMP
WHERE EMP_TYPE = 123
这个语句被ORACLE转换为:
SELECT …
FROM EMP
WHERE TO_NUMBER(EMP_TYPE)=123
因为内部发生的类型转换, 这个索引将不会被用到!
译者按:
为了避免ORACLE对你的SQL进行隐式的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE会优先转换数值类型到字符类型.
45.需要当心的WHERE子句
某些SELECT 语句中的WHERE子句不使用索引. 这里有一些例子.
在下面的例子里, ‘!=’ 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中.
不使用索引:
SELECT ACCOUNT_NAME
FROM TRANSACTION
WHERE AMOUNT !=0;
使用索引:
SELECT ACCOUNT_NAME
FROM TRANSACTION
WHERE AMOUNT >0;
下面的例子中, ‘||’是字符连接函数. 就象其他函数那样, 停用了索引.
不使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME||ACCOUNT_TYPE=’AMEXA’;
使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME = ‘AMEX’
AND ACCOUNT_TYPE=’ A’;
下面的例子中, ‘+’是数学函数. 就象其他数学函数那样, 停用了索引.
不使用索引:
SELECT ACCOUNT_NAME, AMOUNT
FROM TRANSACTION
WHERE AMOUNT + 3000 >5000;
使用索引:
SELECT ACCOUNT_NAME, AMOUNT
FROM TRANSACTION
WHERE AMOUNT > 2000 ;
下面的例子中,相同的索引列不能互相比较,这将会启用全表扫描.
不使用索引:
SELECT ACCOUNT_NAME, AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME = NVL(:ACC_NAME,ACCOUNT_NAME);
使用索引:
SELECT ACCOUNT_NAME, AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME,’%’);
译者按:
如果一定要对使用函数的列启用索引, ORACLE新的功能: 基于函数的索引(Function-Based Index) 也许是一个较好的方案.
CREATE INDEX EMP_I ON EMP (UPPER(ename)); /建立基于函数的索引/
SELECT * FROM emp WHERE UPPER(ename) = ‘BLACKSNAIL’; /将使用索引/
46.连接多个扫描
如果你对一个列和一组有限的值进行比较, 优化器可能执行多次扫描并对结果进行合并连接.
举例:
SELECT *
FROM LODGING
WHERE MANAGER IN (‘BILL GATES’,’KEN MULLER’);
优化器可能将它转换成以下形式
SELECT *
FROM LODGING
WHERE MANAGER = ‘BILL GATES’
OR MANAGER = ’KEN MULLER’;
当选择执行路径时, 优化器可能对每个条件采用LODGINGMANAGER上的索引范围扫描.返回的ROWID用来访问LODGING表的记录(通过TABLEACCESSBYROWID的方式).最后两组记录以连接(CONCATENATION)的形式被组合成一个单一的集合.ExplainPlan:SELECTSTATEMENTOptimizer=CHOOSECONCATENATIONTABLEACCESS(BYINDEXROWID)OFLODGINGINDEX(RANGESCAN)OFLODGINGMANAGER上的索引范围扫描. 返回的ROWID用来访问LODGING表的记录(通过TABLE ACCESS BY ROWID 的方式). 最后两组记录以连接(CONCATENATION)的形式被组合成一个单一的集合. Explain Plan : SELECT STATEMENT Optimizer=CHOOSE CONCATENATION TABLE ACCESS (BY INDEX ROWID) OF LODGING INDEX (RANGE SCAN ) OF LODGINGMANAGER上的索引范围扫描.返回的ROWID用来访问LODGING表的记录(通过TABLEACCESSBYROWID的方式).最后两组记录以连接(CONCATENATION)的形式被组合成一个单一的集合.ExplainPlan:SELECTSTATEMENTOptimizer=CHOOSECONCATENATIONTABLEACCESS(BYINDEXROWID)OFLODGINGINDEX(RANGESCAN)OFLODGINGMANAGER (NON-UNIQUE)
TABLE ACCESS (BY INDEX ROWID) OF LODGING
INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE)
译者按:
本节和第37节似乎有矛盾之处.

47.CBO下使用更具选择性的索引
基于成本的优化器(CBO, Cost-Based Optimizer)对索引的选择性进行判断来决定索引的使用是否能提高效率.
如果索引有很高的选择性, 那就是说对于每个不重复的索引键值,只对应数量很少的记录.
比如, 表中共有100条记录而其中有80个不重复的索引键值. 这个索引的选择性就是80/100 = 0.8 . 选择性越高, 通过索引键值检索出的记录就越少.
如果索引的选择性很低, 检索数据就需要大量的索引范围查询操作和ROWID 访问表的
操作. 也许会比全表扫描的效率更低.
译者按:
下列经验请参阅:
a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高.
b. 在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的
区别. 而通常情况下,使用索引比全表扫描要块几倍乃至几千倍!
48.避免使用耗费资源的操作
带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL语句会启动SQL引擎
执行耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序.
例如,一个UNION查询,其中每个查询都带有GROUP BY子句, GROUP BY会触发嵌入排序(NESTED SORT) ; 这样, 每个查询需要执行一次排序, 然后在执行UNION时, 又一个唯一排序(SORT UNIQUE)操作被执行而且它只能在前面的嵌入排序结束后才能开始执行. 嵌入的排序的深度会大大影响查询的效率.
通常, 带有UNION, MINUS , INTERSECT的SQL语句都可以用其他方式重写.
译者按:
如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, INTERSECT也是可以考虑的, 毕竟它们的可读性很强

49.优化GROUP BY
提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个查询返回相同结果但第二个明显就快了许多.
低效:
SELECT JOB , AVG(SAL)
FROM EMP
GROUP JOB
HAVING JOB = ‘PRESIDENT’
OR JOB = ‘MANAGER’
高效:
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT’
OR JOB = ‘MANAGER’
GROUP JOB
译者按:
本节和14节相同. 可略过.
50.使用日期
当使用日期是,需要注意如果有超过5位小数加到日期上, 这个日期会进到下一天!
例如:
1.SELECT TO_DATE(‘01-JAN-93’+.99999)
FROM DUAL;

Returns:
’01-JAN-93 23:59:59’
2.
SELECT TO_DATE(‘01-JAN-93’+.999999)
FROM DUAL;

Returns:
’02-JAN-93 00:00:00’
译者按:
虽然本节和SQL性能优化没有关系, 但是作者的功力可见一斑
51.使用显式的游标(CURSORs)
使用隐式的游标,将会执行两次操作. 第一次检索记录, 第二次检查TOO MANY ROWS 这个exception . 而显式游标不执行第二次操作.
52. 优化EXPORT和IMPORT
使用较大的BUFFER(比如10MB , 10,240,000)可以提高EXPORT和IMPORT的速度.
ORACLE将尽可能地获取你所指定的内存大小,即使在内存不满足,也不会报错.这个值至少要和表中最大的列相当,否则列值会被截断.
译者按:
可以肯定的是, 增加BUFFER会大大提高EXPORT , IMPORT的效率. (曾经碰到过一个CASE, 增加BUFFER后,IMPORT/EXPORT快了10倍!)
作者可能犯了一个错误: “这个值至少要和表中最大的列相当,否则列值会被截断. “
其中最大的列也许是指最大的记录大小.
关于EXPORT/IMPORT的优化,CSDN论坛中有一些总结性的贴子,比如关于BUFFER参数, COMMIT参数等等, 详情请查.
53. 分离表和索引
总是将你的表和索引建立在不同的表空间内(TABLESPACES). 决不要将不属于ORACLE内部系统的对象存放到SYSTEM表空间里. 同时,确保数据表空间和索引表空间置于不同的硬盘上.
译者按:
“同时,确保数据表空间和索引表空间置与不同的硬盘上.”可能改为如下更为准确 “同时,确保数据表空间和索引表空间置与不同的硬盘控制卡控制的硬盘上.”
Ⅰ.oracle itcast

安装oracle10g 出现oui.exe停止工作错误
安装oracle10g 出现oui.exe停止工作错误
在安装oracle的时候,出现了oui.exe停止工作的错误提示,这是因为你的oracle安装路径中存在中文,你把你的安装程序放到全英文的路径下,重新执行setup.exe就能正常的安装了。就是这么简单

本文档对应程序在myeclipse的jdbc/src/下

Oracle 安装自动生成sys用户和system用户
sys 超级用户 具有最高权限 具有sysDBA角色,有create database权限
该用户默认密码是change_in_install
system 管理操作员 权限也比较大,具有sysoper角色,没有create database权限。
该用户默认密码是 manager
这是通过sqlplus客户端连接数据库时有多个实例 采用下面DOS命令:sqlplus scott/tiger@zhulin
见2.13 oracle创建数据库实例
启动sqlplus,然后登陆数据库出现错误:TNS:协议适配器错误
原因有3个:
1.监听服务没有启动:services.msc或开始—>程序—>管理工具—>服务,打开服务面板:
启动oraclehome92TNSlistener服务
2.database instance没有启动:services.msc或开始—>程序—>管理工具—>服务 启动oralceserviceXXX,XXX就是你databaseSID如zhulin
3.注册表问题:
regedit.msc
进入HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_OraDb11g_home1
下的ORACLE_SID值修改为zhulin

你的全局数据库名字 你的数据库SID即可。

ORACLE用SYS和SYSTEM默认密码登录提示ORA-01017:invalid username/password;logond denied该怎么解决?
解决办法:
有可能是你在建数据库的时候,
修改了默认的密码
而自己又忘记
你可再重新修改过来
sqlplus / as sysdba
alter user system identified by manager;
alter user sys identified by manager;
或者改成其他的你自己容易记住的
默认scott用户密码是tiger

1.oralce解锁步骤
先使用system登录
然后输入alter user scott account unlock; //解锁scott账号
SQL语句必须带分号!!!最好都分号结束

2.oralce开发工具
sqlpulsw和sqlus工具
在开始→程序→oracle oradb_home10g→application development→sqlplus
或在运行栏输入sqlplus
pl/sql developer 这款软件用的很多 第三方软件 需要单独安装
企业管理器(web) 首先保证相关服务启动即oracleDBconsole+实例名启动
在浏览器中输入http://ip:1158//em ip是指你的具体ip地址或者你的机器名 1158是端口
一般情况下 这个服务是不启动 很不安全

3.oracle常用sql plus命令
(1)请使用scott用户登录oracle数据库实例,然后切换为身份为system
简单使用 conn 用户名/密码
登录后,使用 conn[ect] 用户名/密码@网络 [as sysdba/sysoper]
(2)show user 显示当前用户名
(3) 断开连接 disc[onnect]
(4)exit 断开连接和退出sqlplus窗口
(5) 修改密码(前提是system或sys用户) passw[ord]
基本用法 password 用户名
如果给自己修改密码 则可以不带用户名
如果给别人修改密码 则需要带用户名
(6) & 交互命令 可以替代变量的值
select * from emp where job=”&job”;
(7)edit 用于编辑脚本(文本)
SQL>edit d:
(8)spool 把屏幕上显示的记录,保存到文件中
spool on
spool d:/bak.sql
查询语句
spool off
(9)linesize 用户控制每行显示多少个字符,默认80个字符 每次都要重新设置
基本用法: set linesize 120
(10)pagesize 用于每页显示多少行
基本用法: set pagesize 100

4.oracle用户管理
(1)创建用户 只有具有DBA权限才能创建比如system sys
基本用法:create user 用户名 identified by 密码
举例:create user xiaoqiang identified by hao200881037[oracle要求用户密码不能用数字开头]

后面我将密码修改为了200881037
?为什么创建的用户无法登陆
这是因为oracle 刚刚创建的用户是没有任何权限,需要管理员给用户分配适应的权限,才能够登陆
grant create session to xiaoqiang //会话权限

(1)权限
系统权限:和数据库管理相关的权限:
create session;create table;create index;create view;create sequence;create trigger
对象权限:和用户操作数据对象相关的权限:
update;insert;delete;select
(2)角色
预定义角色:把常用的权限集中起来,形成角色(套餐)
比如dba connect resource 三种角色
自定义角色:自己定义套餐
(3)方案(schema)
在一个数据库实例下:
当一个用户,创建好后,如果该用户创建了任意一个数据对象(表或触发器等),这时我们的DBMS就会创建一个对应的方案与该用户对应,并且该方案名字和用户名一致。
小技巧:如果希望看到某个用户的方案的数据对象,可以使用PL/SQL developer工具

案例1:完成一个功能;让xiaoqiang用户去查询scott的emp表
步骤1:先用scott登录
conn scott/tiger
步骤2:在scott账号上给xiaoqiang赋权限
grant select[update|delete|insert|all] on emp to xiaoqiang
这里就可以看出来 方案A和方案B可以有相同名的数据库,但是方案A中不可以有相同名的数据库
步骤3:登录xiaoqiang用户去查询emp表
错误用法:select * from emp 原因是在xiaoqiang登录状态下需要制定emp表来自哪里?
正确用法:select * from scott.emp;
查询时如果查询其他方案 一定要用带上其他方案名。
如果不带,就默认是select * from xiaoqiang.emp

案例2:完成一个功能想办法将xiaoqiang拥有的对scott.emp的权限转给stu用户。
scott—>xiaoqiang—>stu[权限转移]
conn scott/tiger;
grant all on scott.emp to stu with grant option;

//with grant option 对象权限 表示得到权限的用户可以把权限继续分配
//with admin option系统权限 如果是系统权限,则带with admin iption

创建了普通账户 xiaoqiang 密码hao200881037
修改密码(前提是system或sys用户) passw[ord]
基本用法 password 用户名
如果给自己修改密码 则可以不带用户名
如果给别人修改密码 则需要带用户名

表空间:表存在的空间,一个表空间就是指向具体的数据文件

(4)用户管理的综合案例
创建的新用户是没有任何权限的,甚至连登录(会话)的数据库的权限都没有,需要为其指定响应的权限,给一个用户赋权限使用命令grant,回收权限revoke
grant 权限/角色 to 用户

(1) 使用system创建xiaoqiang

后面我将密码修改为了200881037
(2) 使用system给小红分配2个常用角色
grant connect to xiaoqiang
grant resource to xiaoqiang
disconn //切断连接
(3) 让xiaoqiang登录
conn xiaoqiang/200881037
(4) xiaoqiang修改密码 pasw[ord] xiaoqiang即可 然要求你输入旧密码 当然 超级管理员不需要输入旧密码
(5) xiaohong创建一张最简单的表

(6) 使用system登录,然后回收角色。
revoke connect from xiaoqiang
revoke resource from xiaoqiang
(7) 删除xiaoqiang用户:
drop user 用户名[cascade]
☞当我们删除一个用户的时候,若这个用户自己已经创建了数据对象(表、触发器等),需要加选项cascade表示把这个用户删除同时,把该用户创建的数据对象一并删除。
否则无法删除该用户,oracle用户认为删除了该用户就彻底抛弃了

(5)账号锁定
使用profile管理用户口令,账号锁定指用户登录时最多可以输入密码的次数,也可以指定用户锁定的时间(天)一般用DBA的身份去执行该命令。 profile文件[规则]
eg:
create profile lock_account limit failed_login_attempts 3 paswword_lock_time 2;
alter user tea profile lock_account;//其中lock_account是文件名
(6)账号解锁
alter user 用户名 account unlock;
(7)终止口令
eg:给tea创建一个profile文件,要求该用户每隔10天必须修改自家的登录密码,款限期为2天。
create profile myprofile limit password_life_time 10 password_grace_time 2;
//可以继续加限制条件
alter user tea profile myprofile;
(8)删除profile文件
当不需要某个profile文件时,可以删除该文件。
drop profile profile文件名。

5.oracle数据库启动流程
oracle可以通过命令行的方式启动,我们看看具体如何操作:
windows下:
(1)lsnrctl start (启动监听)
(2)oradim –startup –sid 数据库实例名
linux下:
(1) lsnrctl start (启动监听)
(2) sqlplus sys/chang_on_install as sysdba(以sysdba身份登录)
sqlplus /nolog
conn sys/chang_on_install as sysdba
(3)startup

6.oracle登录认证方式
oracle在windows和linux下是不完全相同的:
windows下:
如果当前用户属于本地操作系统的ora_dba组(对于windows操作系统而言),即可通过操作系统认证。
普通用户:默认是以数据库方式认证,比如conn scott/tiger;
特权用户:默认是以操作系统认证(即:只要当前用户是在ora_dba组中则可以通过认证),比如conn system/manager as sysdba;DBMS一看到as sysdba则认为 要以特权用户登录,前面的用户名和密码不看,登录后自动切换成sys用户<=>conn sys/manager。
如果当前用户(win7系统账号)不在ora_dba组中,conn sys/manager 输对了密码还是可以登录进去的(这时是采用了数据库方式验证)
sqlnet.ora文件在D:\xiaoqiang\oracle\product\11.2.0\dbhome_1\NETWORK\ADMIN目录下:
同时如果你安装第三方工具PL/SQL Developer,同时也需要修改
D:\xiaoqiang\oracle\product\instantclient_11_2目录下的sqlnet.ora文件
通过配置sqlnet.ora文件,可以修改oracle登录认证方式:
SQLNET.AUTHENTICATION_SERVICES=(NTS)是基于操作系统验证
SQLNET.AUTHENTICATION_SERVICES=(NONE)是基于Oracle验证
SQLNET.AUTHENTICATION_SERVICES=(NONE,NTS)是二者共存

linux下:
默认情况下linux下的oracle数据库sqlnet.ora文件没有SQLNET.AUTHENTICATION_SERVICES参数,此时是基于操作系统认真和oracle密码验证共存,加上SQLNET.AUTHENTICATION_SERVICES参数后,不管SQLNET.AUTHENTICATION_SERVICES设置为NONE还是NTS都是基于oracle密码验证。

7.oracle丢失管理员密码怎么办
数据库实例名是根据实际情况命名的。
恢复办法:把原有密码文件删除,生成一个新的密码文件
恢复步骤如下:(1)搜索名为PWD数据库实例名.ora文件
(2)删除该文件,为以防万一,建议备份
(3)生成新的密码文件,在DOS控制台下输入命令
orapwd file=原来密码文件的全路径\密码文件名.ora password=新密码 entries=10;
这里密码文件名是原来的密码文件名=PWD数据库实例名
entries 表示登录sys的最多用户(特权用户)
如果希望新的密码生效,则需要重新启动数据库实例服务.dos下services.exe

还有出现以下情况:
ORACLE用SYS和SYSTEM默认密码登录提示ORA-01017:invalid username/password;logond denied该怎么解决?
解决办法:
有可能是你在建数据库的时候,
修改了默认的密码
而自己又忘记
你可再重新修改过来
sqlplus / as sysdba
alter user system identified by manager;
alter user sys identified by manager;
或者改成其他的你自己容易记住的
默认scott用户密码是tiger

8.oracle表管理
类(对象)和表(记录)之间的关系

◆创建表
基本语法

◆数据类型
① char(size) 存放字符串 最大2000个字符,是定长
eg:char(32) 最多只能放入32个字符 如果超过 就报错,如果不够’abc’则用空格补全
② varchar2(size) 变长 最大可以存放4000个字符
③ nchar(size) 定长 编码方式unicode 最大字符数是2000个
一个汉字占用nchar的一个字符空间,一个汉字,占用char的两个字符空间
④ nvarchar2(size) 变长 编码方式unicode最大字符数是4000个
⑤ clob 字符型大对象 变长 最大8TB
⑥ blob 变长
说明:我们在实际开发中很少把文件存放在数据库中(效率问题),实际上我们一般记录文件的一个路径(URL或本地路径),然后通过IO或网络来操作。
如果我们要求对文件安全性比较高,可以考虑放入数据库。

⑦ number(p,s)   p为整数位,s为小数位,范围是1<=p<=38,-84<=s<=-127  变长保存数据范围:-1.0e-130<=number value<=1.0e+126  保存机器位数1-22bytee.g number(5,2) 表示一个小数有5位有效位,2位小数,范围-999,99-999,99比如你输入 573.316则真正保存是573.32,无法保存数据1000

number(5)等价于number(5,0),表示一个5位整数,范围-99999-99999,输入57523.316则保存57523
原则:如果在做实际开发中,我们没有指定数据小数位,则直接使用number
⑧date 日期类型
包含年月日,时分秒
插入数据时要使用默认格式是:‘dd-mm-yyy’;当然 如果用自己格式需要借用to_date函数
SQL> insert into test1 values(to_date(‘2005-11-11’,‘YYYY-MM-DD’));
1 row inserted
to_char
你可以使用select ename, hiredate, sal from emp where deptno = 10;显示信息,可是,在某些情况下,这个并不能满足你的需求。
问题:日期是否可以显示 时/分/秒
SQL> select ename, to_char(hiredate, ‘yyyy-mm-dd hh24:mi:ss’) from emp;

9.oracle基本查询
oracle的crud操作(create retrieve/read update delete)

添加一个字段
SQL>ALTER TABLE student add (classId NUMBER(2));
修改一个字段的长度
SQL>ALTER TABLE student modify (xm VARCHAR2(30));
修改字段的类型/或是名字(不能有数据) 不建议做
SQL>ALTER TABLE student modify (xm CHAR(30));
删除一个字段 不建议做(删了之后,顺序就变了。加就没问题,应为是加在后面)
SQL>ALTER TABLE student DROP COLUMN sal;
修改表的名字 很少有这种需求
SQL>RENAME student TO stu;
删除表
SQL>DROP TABLE student;

添加数据
所有字段都插入数据
INSERT INTO student VALUES (‘A001’, ‘张三’, ‘男’, ‘01-5月-05’, 10);
oracle中默认的日期格式‘dd-mon-yy’ dd日子(天) mon 月份 yy 2位的年 ‘09-6月-99’ 1999年6月9日
修改日期的默认格式(临时修改,数据库重启后仍为默认;如要修改需要修改注册表)
ALTER SESSION SET NLS_DATE_FORMAT =‘yyyy-mm-dd’;
修改后,可以用我们熟悉的格式添加日期类型:
INSERT INTO student VALUES (‘A002’, ‘MIKE’, ‘男’, ‘1905-05-06’, 10);
插入部分字段
INSERT INTO student(xh, xm, sex) VALUES (‘A003’, ‘JOHN’, ‘女’);
插入空值
INSERT INTO student(xh, xm, sex, birthday) VALUES (‘A004’, ‘MARTIN’, ‘男’, null);
问题来了,如果你要查询student表里birthday为null的记录,怎么写sql呢?
错误写法:select * from student where birthday = null;
正确写法:select * from student where birthday is null;
如果要查询birthday不为null,则应该这样写:
select * from student where birthday is not null;

修改数据
修改一个字段
UPDATE student SET sex = ‘女’ WHERE xh = ‘A001’;
修改多个字段
UPDATE student SET sex = ‘男’, birthday = ‘1984-04-01’ WHERE xh = ‘A001’;
修改含有null值的数据
不要用 = null 而是用 is null;
SELECT * FROM student WHERE birthday IS null;

删除数据
DELETE FROM student;
删除所有记录,表结构还在,写日志,可以恢复的,速度慢。
Delete 的数据可以恢复。
savepoint a; --创建保存点
DELETE FROM student;
rollback to a; --恢复到保存点
一个有经验的DBA,在确保完成无误的情况下要定期创建还原点。
DROP TABLE student; --删除表的结构和数据;
delete from student WHERE xh = ‘A001’; --删除一条记录;
truncate TABLE student; --删除表中的所有记录,表结构还在,不写日志,无法找回删除的记录,速度快。

oracle基本所有查询案例
在我们讲解的过程中我们利用scott用户存在的几张表(emp,dept)为大家演示如何使用select语句,select语句在软件编程中非常有用,希望大家好好的掌握。

查看表结构
DESC emp;
查询所有列
SELECT * FROM dept;
切忌动不动就用select *
SET TIMING ON; 打开显示操作时间的开关,在下面显示查询时间。
CREATE TABLE users(userId VARCHAR2(10), uName VARCHAR2 (20), uPassw VARCHAR2(30));
INSERT INTO users VALUES(‘a0001’, ‘啊啊啊啊’, ‘aaaaaaaaaaaaaaaaaaaaaaa’);
–从自己复制,加大数据量 大概几万行就可以了 可以用来测试sql语句执行效率
INSERT INTO users (userId,UNAME,UPASSW) SELECT * FROM users;
SELECT COUNT (*) FROM users;统计行数

查询指定列
SELECT ename, sal, job, deptno FROM emp;
如何取消重复行DISTINCT
SELECT DISTINCT deptno, job FROM emp;
查询SMITH所在部门,工作,薪水
SELECT deptno,job,sal FROM emp WHERE ename = ‘SMITH’;
注意:oracle对内容的大小写是区分的,所以ename='SMITH’和ename='smith’是不同的

使用算术表达式 nvl null
问题:如何显示每个雇员的年工资?
SELECT sal*13+nvl(comm, 0)13 “年薪” , ename, comm FROM emp;
使用列的别名
SELECT ename “姓名”, sal
12 AS “年收入” FROM emp;
如何处理null值使用nvl函数来处理
如何连接字符串(||)
SELECT ename || ’ is a ’ || job FROM emp;
使用where子句
问题:如何显示工资高于3000的 员工?
SELECT * FROM emp WHERE sal > 3000;
问题:如何查找1982.1.1后入职的员工?
SELECT ename,hiredate FROM emp WHERE hiredate >‘1-1月-1982’;
问题:如何显示工资在2000到3000的员工?
SELECT ename,sal FROM emp WHERE sal >=2000 AND sal <= 3000;

如何使用like操作符
%:表示0到多个字符 _:表示任意单个字符
问题:如何显示首字符为S的员工姓名和工资?
SELECT ename,sal FROM emp WHERE ename like ‘S%’;
如何显示第三个字符为大写O的所有员工的姓名和工资?
SELECT ename,sal FROM emp WHERE ename like ‘__O%’;

在where条件中使用in
问题:如何显示empno为7844, 7839,123,456 的雇员情况?
SELECT * FROM emp WHERE empno in (7844, 7839,123,456);
使用is null的操作符
问题:如何显示没有上级的雇员的情况?
错误写法:select * from emp where mgr = ‘’;
正确写法:SELECT * FROM emp WHERE mgr is null;

使用逻辑操作符号
问题:查询工资高于500或者是岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J?
SELECT * FROM emp WHERE (sal >500 or job = ‘MANAGER’) and ename LIKE ‘J%’;
使用order by字句 默认asc
问题:如何按照工资的从低到高的顺序显示雇员的信息?
SELECT * FROM emp ORDER by sal;
问题:按照部门号升序而雇员的工资降序排列
SELECT * FROM emp ORDER by deptno, sal DESC;

使用列的别名排序
问题:按年薪排序
select ename, (sal+nvl(comm,0))*12 “年薪” from emp order by “年薪” asc;
别名需要使用“”号圈中,英文不需要“”号

Clear 清屏命令

数据分组 ——max,min, avg, sum, count
问题:如何显示所有员工中最高工资和最低工资?
SELECT MAX(sal),min(sal) FROM emp e;
最高工资那个人是谁?
错误写法:select ename, sal from emp where sal=max(sal);
正确写法:select ename, sal from emp where sal=(select max(sal) from emp);
注意:select ename, max(sal) from emp;这语句执行的时候会报错,说ORA-00937:非单组分组函数。因为max是分组函数,而ename不是分组函数…
但是select min(sal), max(sal) from emp;这句是可以执行的。因为min和max都是分组函数,就是说:如果列里面有一个分组函数,其它的都必须是分组函数,否则就出错。这是语法规定的问题:如何显示所有员工的平均工资和工资总和?

问题:如何计算总共有多少员工问题:如何
扩展要求:
查询最高工资员工的名字,工作岗位
SELECT ename, job, sal FROM emp e where sal = (SELECT MAX(sal) FROM emp);
显示工资高于平均工资的员工信息
SELECT * FROM emp e where sal > (SELECT AVG(sal) FROM emp);

group by 和 having子句
group by用于对查询的结果分组统计 having子句用于限制分组显示结果

问题:如何显示每个部门的平均工资和最高工资?
SELECT AVG(sal), MAX(sal), deptno FROM emp GROUP by deptno;
(注意:这里暗藏了一点,如果你要分组查询的话,分组的字段deptno一定要出现在查询的列表里面,否则会报错。因为分组的字段都不出现的话,就没办法分组了)

问题:显示每个部门的每种岗位的平均工资和最低工资?
SELECT min(sal), AVG(sal), deptno, job FROM emp GROUP by deptno, job;

问题:显示平均工资低于2000的部门号和它的平均工资?
SELECT AVG(sal), MAX(sal), deptno FROM emp GROUP by deptno having AVG(sal) < 2000;

对数据分组的总结
1 分组函数只能出现在选择列表、having、order by子句中(不能出现在where中)
2 如果在select语句中同时包含有group by, having, order by 那么它们的顺序是group by, having, order by
3 在选择列中如果有列、表达式和分组函数,那么这些列和表达式必须有一个出现在group by 子句中,否则就会出错。
如SELECT deptno, AVG(sal), MAX(sal) FROM emp GROUP by deptno HAVING AVG(sal) < 2000;
这里deptno就一定要出现在group by 中

问题:显示雇员名,雇员工资及所在部门的名字【笛卡尔集】?
规定:多表查询的条件是 至少不能少于 表的个数-1 才能排除笛卡尔集
(如果有N张表联合查询,必须得有N-1个条件,才能避免笛卡尔集合)
SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno;

问题:显示部门号为10的部门名、员工名和工资?
SELECT d.dname, e.ename, e.sal FROM emp e, dept d WHERE e.deptno = d.deptno and e.deptno = 10;

问题:显示各个员工的姓名,工资及工资的级别?
先看salgrade的表结构和记录
SQL>select * from salgrade;
GRADE LOSAL HISAL


    1          700           1200 2          1201          1400 3          1401          2000 4          2001          3000 5          3001          9999

SELECT e.ename, e.sal, s.grade FROM emp e, salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal;

扩展要求:
问题:显示雇员名,雇员工资及所在部门的名字,并按部门排序?
SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno ORDER by e.deptno;
(注意:如果用group by,一定要把e.deptno放到查询列里面)

自连接
自连接是指在同一张表的连接查询
问题:显示某个员工的上级领导的姓名?
比如显示员工‘FORD’的上级
SELECT worker.ename, boss.ename FROM emp worker,emp boss WHERE worker.mgr = boss.empno AND worker.ename = ‘FORD’;

请思考:显示与SMITH同部门的所有员工?
思路:
1 查询出SMITH的部门号
select deptno from emp WHERE ename = ‘SMITH’;
2 显示
SELECT * FROM emp WHERE deptno = (select deptno from emp WHERE ename = ‘SMITH’);
数据库在执行sql 是从左到右扫描的, 如果有括号的话,括号里面的先被优先执行。

请思考:如何查询和部门10的工作相同的雇员的名字、岗位、工资、部门号
SELECT DISTINCT job FROM emp WHERE deptno = 10;
SELECT * FROM emp WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno = 10);
(注意:不能用job=…,因为等号=是一对一的)

在多行子查询中使用all操作符
问题:如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号?
SELECT ename, sal, deptno FROM emp WHERE sal > all (SELECT sal FROM emp WHERE deptno = 30);
扩展要求:
大家想想还有没有别的查询方法。
SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30);
执行效率上, 函数高得多

在多行子查询中使用any操作符
问题:如何显示工资比部门30的任意一个员工的工资高的员工姓名、工资和部门号?
SELECT ename, sal, deptno FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 30);
扩展要求:
大家想想还有没有别的查询方法。
SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT min(sal) FROM emp WHERE deptno = 30);

多列子查询
单行子查询是指子查询只返回单列、单行数据,多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询是指查询返回多个列数据的子查询语句。
请思考如何查询与SMITH的部门和岗位完全相同的所有雇员。
SELECT deptno, job FROM emp WHERE ename = ‘SMITH’;
SELECT * FROM emp WHERE (deptno, job) = (SELECT deptno, job FROM emp WHERE ename = ‘SMITH’);
在from子句中使用子查询
请思考:如何显示高于自己部门平均工资的员工的信息
思路:

  1. 查出各个部门的平均工资和部门号
    SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno;
  2. 把上面的查询结果看做是一张子表
    SELECT e.ename, e.deptno, e.sal, ds.mysal FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) ds WHERE e.deptno = ds.deptno AND e.sal > ds.mysal;
    如何衡量一个程序员的水平?
    网络处理能力, 数据库, 程序代码的优化程序的效率要很高
    小总结:
    在这里需要说明的当在from子句中使用子查询时,该子查询会被作为一个视图来对待,因此叫做内嵌视图,当在from子句中使用子查询时,必须给子查询指定别名。
    注意:别名不能用as,如:SELECT e.ename, e.deptno, e.sal, ds.mysal FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) as ds WHERE e.deptno = ds.deptno AND e.sal > ds.mysal;
    在ds前不能加as,否则会报错 (给表取别名的时候,不能加as;但是给列取别名,是可以加as的)

10.oracle分页查询
mysql: select * from 表名 where 条件 limit 从第几条取,取几条 见mysql分页查询
sql server: select top 取几条 * from 表名 where id not in(select top 4 id from 表名 where 条件) 也可以使用行集函数 见3.sql server分页查询
排除前4条,再取4条,这个案例实际上是取5-8条
oracle:

以scott/tiger账号登陆进行查询:[分页查询模板]
select t2.* from
(select t1.,rownum rn from
(select * from emp) t1
where rownum<=6) t2 where rn>=4;
先找到小于6的 然后找到大于4的
【顺序可以反】
select t2.
from
(select t1.,rownum rn from
(select * from emp) t1
where rownum>=4) t2 where rn<=6;
oracle使用三层过滤:
第一层:select * from emp
第二层: select t1.
,rownum rn from (select * from emp) t1
where rownum<=6
第三层: select t2.* from
(select t1.*,rownum rn from
(select * from emp) t1
where rownum<=6) t2 where rn>=4;
上面是一个分页模板,6表示取到第几条,4表示从第几条取
(1)删除重复记录
在几千条记录里,存在着些相同的记录,请用sql语句删除。
【注意】1.表中肯定是没有主键的,这才叫记录相同
2.若有主键(主键肯定不同),那请你把其他字段变成一个临时表,再使用下面方法
准备:

11.oracle合并查询
有时在实际应用中,为了合并多个select语句的结果,可以使用集合操作符号union,union all,intersect,minus 多用于数据量比较大的数据局库,运行速度快。
1). union
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行。
SELECT ename, sal, job FROM emp WHERE sal >2500
UNION
SELECT ename, sal, job FROM emp WHERE job = ‘MANAGER’;
2).union all
该操作符与union相似,但是它不会取消重复行,而且不会排序。
SELECT ename, sal, job FROM emp WHERE sal >2500
UNION ALL
SELECT ename, sal, job FROM emp WHERE job = ‘MANAGER’;
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行。
3). intersect 使用该操作符用于取得两个结果集的交集。
SELECT ename, sal, job FROM emp WHERE sal >2500
INTERSECT
SELECT ename, sal, job FROM emp WHERE job = ‘MANAGER’;
4). minus 使用改操作符用于取得两个结果集的差集,他只会显示存在第一个集合中,而不存在第二个集合中的数据。
SELECT ename, sal, job FROM emp WHERE sal >2500
MINUS
SELECT ename, sal, job FROM emp WHERE job = ‘MANAGER’;
(MINUS就是减法的意思)

12.oracle连接
(1)内连接:使我们用的最多的一种连接,前面我们使用的都是内连接。
eg:显示员工的信息和部门名称
select emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno;
等价于
select emp.ename,dept.dname from emp inner join dept on emp.deptno=dept.deptno;
基本语法:select 字段1, 字段2… from 表名1 inner join 表名2 on 条件
(2)外连接:
我们创建2种表做测试:

①左外连接(显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩显示为空)
select stu.id,stu.name,exam.grade from stu left join exam on stu.id=exam.id;
有的程序员喜欢这样写 左外连接:
select stu.id,stu.name,exam.grade from stu,exam where stu.id=exam.id(+);

②右外连接(显示所有成绩,如果没有名字匹配,显示为空)
select stu.id,stu.name,exam.grade from stu right join exam on stu.id=exam.id;
有的程序员喜欢这样写 左外连接:
select stu.id,stu.name,exam.grade from stu,exam where stu.id(+)=exam.id;
③完全外连接(显示所有成绩和所有人的名字,如果响应的匹配值,则显示为空)不管有无匹配均显示
select stu.id,stu.name,exam.grade from stu full outer join exam on stu.id=exam.id;

13.oracle函数
(1)字符函数
字符函数是oracle中最常用的函数,我们来看看有哪些字符函数:
lower(char):将字符串转化为小写的格式.
upper(char):将字符串转化为大写的格式.
length(char):返回字符串的长度。
substr(char,m,n):取字符串的子串;n代表取n个的意思,不是代表取到第n个
replace(char1,search_string,replace_string)
instr(char1,char2,[,n[,m]])取子串在字符串的位置
问题:将所有员工的名字按小写的方式显示
SQL> select lower(ename) from emp;
问题:将所有员工的名字按大写的方式显示。
SQL> select upper(ename) from emp;
问题:显示正好为5个字符的员工的姓名。
SQL> select * from emp where length(ename)=5;
问题:显示所有员工姓名的前三个字符。
SQL> select substr(ename,1,3) from emp;
问题:以首字母大写,后面小写的方式显示所有员工的姓名。
SQL> select upper(substr(ename,1,1)) || lower(substr(ename,2,length(ename)-1)) from emp;
问题:以首字母小写,后面大写的方式显示所有员工的姓名。
SQL> select lower(substr(ename,1,1)) || upper(substr(ename,2,length(ename)-1)) from emp;
问题:显示所有员工的姓名,用“我是老虎”替换所有“A”
SQL> select replace(ename,‘A’, ‘我是老虎’) from emp;
(2)数学函数
数学函数的输入参数和返回值的数据类型都是数字类型的。数学函数包括cos,cosh,exp,ln, log,sin,sinh,sqrt,tan,tanh,acos,asin,atan,round,我们讲最常用的:
round(n,[m])该函数用于执行四舍五入,如果省掉m,则四舍五入到整数,如果m是正数, 则四舍五入到小数点的m位后。如果m是负数,则四舍五入到小数点的m位前。
trunc(n,[m]) 该函数用于截取数字。若省掉m,就截去小数部分(等价于trunc(n,0)),如 果m是正数就截取到小数点的m位后,若m是负数,则截取到小数点的前m位。
mod(m,n)
floor(n) 返回小于或是等于n的最大整数
ceil(n) 返回大于或是等于n的最小整数
问题:显示在一个月为30天的情况下,所有员工的日薪金,忽略余数。
SQL> select trunc(sal/30), ename from emp;
or
SQL> select floor(sal/30), ename from emp;
在做oracle测试的时候,可以使用dual表
select mod(10,2) from dual;结果是0
select mod(10,3) from dual;结果是1
其它的数学函数,有兴趣的同学可以自己去看看:
abs(n): 返回数字n的绝对值
select abs(-13) from dual;
acos(n): 返回数字的反余弦值
asin(n): 返回数字的反正弦值
atan(n): 返回数字的反正切值
cos(n):
exp(n): 返回e的n次幂
log(m,n): 返回对数值
power(m,n): 返回m的n次幂
(3)日期函数
日期函数用于处理date类型的数据。
默认情况下日期格式是dd-mon-yy 即12-7月-78
(1)sysdate: 该函数返回系统时间
(2)add_months(d,n) 在日期d上增加n个月
(3)last_day(d):返回指定日期所在月份的最后一天
问题:查找已经入职8个月多的员工
SQL> select * from emp where sysdate>=add_months(hiredate,8);
问题:显示满10年服务年限的员工的姓名和受雇日期。
SQL> select ename, hiredate from emp
where sysdate>=add_months(hiredate,12*10);
问题:对于每个员工,显示其加入公司的天数。
SQL> select floor(sysdate-hiredate) “入职天数”,ename from emp;
or
SQL> select trunc(sysdate-hiredate) “入职天数”,ename from emp;
(4)给表取别名的时候,不能加as;但是给列取别名,是可以加as
问题:找出各月倒数第3天受雇的所有员工。
SQL> select hiredate,ename from emp where last_day(hiredate)-2=hiredate;
(5)转换函数
转换函数用于将数据类型从一种转为另外一种。在某些情况下,oracle server允许值的数据类型和实际的不一样,这时oracle server会隐含的转化数据类型
比如:
create table t1(id int);//这里 注意int不是关键字在oracle下
insert into t1 values(‘10’);–>这样oracle会自动的将10 -->'10 ’
create table t2 (id varchar2(10));
insert into t2 values(1); -->这样oracle就会自动的将1 -->‘1’;
我们要说的是尽管oracle可以进行隐含的数据类型的转换,但是它并不适应所有的情况,为了提高程序的可靠性,我们应该使用转换函数进行转换。
(6) to_char(date,‘format’)
你可以使用select ename, hiredate, sal from emp where deptno = 10;显示信息,可是,在某些情况下,这个并不能满足你的需求。
问题:日期是否可以显示 时/分/秒
SQL> select ename, to_char(hiredate, ‘yyyy-mm-dd hh24:mi:ss’) from emp;
问题:薪水是否可以显示指定的货币符号
SQL>
yy:两位数字的年份 2004–>04
yyyy:四位数字的年份 2004年
mm:两位数字的月份 8月–>08
dd:两位数字的天 30号–>30
hh24: 8点–>20
hh12:8点–>08
mi、ss–>显示分钟\秒

9:显示数字,并忽略前面0
0:显示数字,如位数不足,则用0补齐
.:在指定位置显示小数点
,:在指定位置显示逗号
$:在数字前加美元
L:在数字前面加本地货币符号
C:在数字前面加国际货币符号
G:在指定位置显示组分隔符、
D:在指定位置显示小数点符号(.)

问题:显示薪水的时候,把本地货币单位加在前面
SQL> select ename, to_char(hiredate, ‘yyyy-mm-dd hh24:mi:ss’), to_char(sal,‘L99999.99’) from emp;
问题:显示1980年入职的所有员工
SQL> select * from emp where to_char(hiredate, ‘yyyy’)=1980;
问题:显示所有12月份入职的员工
SQL> select * from emp where to_char(hiredate, ‘mm’)=12;
这里的12和1980可以加’'也可以不加,因为Oracle会自动转换,但是最好加。

(7) to_date(string,‘format’)
函数to_date用于将字符串转换成date类型的数据。
问题:能否按照中国人习惯的方式年—月—日添加日期。
SQL> create table test1(id date);
SQL> insert into test1 values(to_date(‘2005-11-11’,‘YYYY-MM-DD’));
1 row inserted

(8)系统函数
sys_context
1)terminal:当前会话客户所对应的终端的标示符
2)lanuage: 语言
3)db_name: 当前数据库名称
4)nls_date_format: 当前会话客户所对应的日期格式
5)session_user: 当前会话客户所对应的数据库用户名
6)current_schema: 当前会话客户所对应的默认方案名
7)host: 返回数据库所在主机的名称
通过该函数,可以查询一些重要信息,比如你正在使用哪个数据库?
SQL>select sys_context(‘USERENV’,‘db_name’) from dual;
SYS_CONTEXT(‘USERENV’,'DB_NAME

zhulin
注意:USERENV是固定的,不能改的,db_name可以换成其它,比如lanuage SQL>sys_context(‘USERENV’,‘lanuage’) from dual;
SYS_CONTEXT(‘USERENV’,'LANGUAG

AMERICAN_AMERICA.ZHS16GBK
SQL>sys_context(‘USERENV’,‘current_schema’) from dual;
SYS_CONTEXT(‘USERENV’,'CURRENT

XIAOQIANG

14.oracle创建数据库实例

创建数据库有两种方法:
1). 通过oracle提供的向导工具。
database Configuration Assistant 【数据库配置助手】
2).我们可以用手工步骤直接创建。
☞但我们创建完一个新的数据库实例后,在服务中(services.exe)中就会有两个新的服务创建,这时,你根据实际需要去启动相应的数据库实例。
☞在同一台机器允许同时启动多个数据库实例,我们在登录或链接的时候需要指定主机字符串(SID )
这是通过sqlplus客户端连接数据库时有多个实例 采用下面DOS命令:sqlplus scott/tiger@zhulin

15.java操作oracle
(1)JDBC连接

补充一下:
SQL语句分类:
DML语句:数据操作语句(insert、update、delete)
DDL语句:数据定义语言(create table、drop table…)
DQL语句:数据查询语言(select)
对于使用java去查询oracle会出现一个很奇怪的现象?
PL/SQL Developer看到的数据库,可能和java程序中看到的数据不一致,这是事务控制引起的。
对java连接oracle 封装成一个OracleSQLHelper类。
//3.创建 PrepareedStatement或Statement接口引用对象
//Statement用处:主要用于发送sql语句到数据库
//PrepareedStatement:会进行预编译,适合批量的sql语句,有效防止危险字符注入
//PrepareedStatement支持在sql语句中出现问号?作为参数带进去!!!
我们把连接数据库的配置信息写到一个文件中去,这样代码更加灵活。
这里有一个Java技巧,快速提供类的get和set方法:

然后弹出一个窗口:
最后OK。
(2)JDBC-ODBC连接
配置数据源——管理工具(Administrative tools)——ODBC——userDSN——Add添加ODBC数据源

java代码做相应的修改:【与SQLserver一样的】//sun.jdbc.odbc.JdbcOdbcDriver本身自带
Class.Forname(“sun.jdbc.odbc.JdbcOdbcDriver”);
Connection ct=DriverManager.getConnection(“jdbc:odbc:hsporc”,“scott”,“tiger”);
这里hsporc就是你ODBC数据源名称了。。。。。。
什么时候用JDBC或JDBC-ODBC?
原则:若java程序和DB不在同一机器上,我们一般使用JDBC
若java程序和DB在同一机器上,我们一般使用JDBC-ODBC

16.oracle事务处理
什么是事务
事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml(数据操作语言,增删改,没有查询)语句要么全部成功,要么全部失败。
如:网上转账就是典型的要用事务来处理,用于保证数据的一致性。
dml 数据操作语言 银行转账、QQ申请、车票购买
事务和锁
当执行事务操作时(dml语句),oracle会在被作用的表上加锁,防止其它用户修改表的结构。这里对我们的用户来来讲是非常重要的。
…其它进程排序,知道1号进程完成,锁打开,2号进程进入。依次进行,如果有进程级别较高的,可以插队。
提交事务
当执行用commit语句可以提交事务。当执行了commit语句之后,会确认事务的变化、结束事务。删除保存点、释放锁,当使用commit语句结束事务之后,其它会话将可以查看到事务变化后的新数据。
保存点就是为回退做的。保存点的个数没有限制
回退事务
在介绍回退事务前,我们先介绍一下保存点(savepoint)的概念和作用。保存点是事务中的一点。用于取消部分事务,当结束事务时,会自动的删除该事务所定义的所有保存点。当执行rollback时,通过指定保存点可以回退到指定的点,这里我们作图说明。

事务的几个重要操作
1.设置保存点 savepoint a
2.取消部分事务 rollback to a
3.取消全部事务 rollback
每个保存点都只有一次回退的机会 设置保存点是有资源开销的 一旦commit了事务则不能回退
注意:这个回退事务,必须是没有commit前使用的;如果事务提交了,那么无论你刚才做了多少个保存点,都统统没有。 如果没有手动执行commit,而是exit了,那么会自动提交
java程序中如何使用事务 ./src/oracle_test/test_oracle_transaction_vital.java
//事先先设置成不自动提交
//事务开始
update emp set=?
insert…
update…
commit();
如果一个事务中,只有select则事务可以忽略,若一个事务有多个(update,insert,delete)则需要考虑事务。

事务的隔离级别:定义了事务与事务之间的隔离程度。
ANSI/ISO SQL92国际标准化组织定义了一个标准,不同的数据库在实现时有所不同。
隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted) √ √ √
读已提交(Read committed) × √ √
可重复读(Repeatable read) × × √
可串行化(Serializable) × × ×
×不会出现 √可能出现
oracle提供了三种隔离级别:读已提交、可串行化、(Read Only 非ANSI/ISO SQL92标准)
脏读(dirty read):当事务A读取事务B尚未提交的修改时,产生脏读。在oracle中不会出现
不可重复读(nonrepeatable read):同一查询在同一事务中多次进行,由于其他提交事务所在的修改或删除,每次返回不同的结果集,此时发生非重复读。
幻读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集(结果集到底是对还是错?),此时发生幻读。

oracle中设置事务隔离级别:
设置一个事务的隔离级别:
set transaction isolation level read committed;(默认级别)
set transaction isolation level serializable;(手动)
设置整个会话的隔离级别:
alter session set isolation_level serializable;
alter session set isolation_level read committed;

java程序中设置事务隔离级别: public Connection ct=null;

说明:一般情况下,我们java程序员无需设置事务的隔离级别。

17.oracle数据完整性
约束:用于确保数据库数据满足特定的商业规则。在oracle中,约束包括:not null、 unique, primary key, foreign key,和check五种。
not null(非空)
如果在列上定义了not null,那么当插入数据时,必须为列提供数据。
unique(唯一)
当定义了唯一约束后,该列值是不能重复的,但是可以为null。
primary key(主键)
用于唯一的标示表行的数据,当定义主键约束后,该列不但不能重复而且不能为null。
需要说明的是:一张表最多只能有一个主键,但是可以有多个unqiue约束。
foreign key(外键)
用于定义主表和从表之间的关系。外键约束要定义在从表上,主表则必须具有主键约束或是unique约束,当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null。
check
用于强制行数据必须满足的条件,假定在sal列上定义了check约束,并要求sal列值在1000-2000之间如果不在1000-2000之间就会提示出错。

商店售货系统表设计案例
现有一个商店的数据库,记录客户及其购物情况,由下面三个表组成:商品goods(商品号goodsId,商品名 goodsName,单价 unitprice,商品类别category,供应商provider);
客户customer(客户号customerId,姓名name,住在address,电邮email,性别sex,身份证cardId);
购买purchase(客户号customerId,商品号goodsId,购买数量nums);
请用SQL语言完成下列功能:

  1. 建表,在定义中要求声明:
    (1). 每个表的主外键;
    (2). 客户的姓名不能为空值;
    (3). 单价必须大于0,购买数量必须在1到30之间;
    (4). 电邮不能够重复;
    (5). 客户的性别必须是 男 或者 女,默认是男;
    SQL> create table goods(goodsId char(8) primary key, --主键
    goodsName varchar2(30),
    unitprice number(10,2) check(unitprice>0),
    category varchar2(8),
    provider varchar2(30)
    );
    SQL> create table customer( customerId char(8) primary key, --主键
    name varchar2(50) not null, --不为空
    address varchar2(50),
    email varchar2(50) unique,
    sex char(2) default ‘男’ check(sex in (‘男’,‘女’)),
    – 一个char能存半个汉字,两位char能存一个汉字
    cardId char(18)
    );
    SQL> create table purchase( customerId char(8) references customer(customerId),
    goodsId char(8) references goods(goodsId),
    nums number(10) check (nums between 1 and 30)
    );
    表是默认建在SYSTEM表空间的

维护
商店售货系统表设计案例(2)
如果在建表时忘记建立必要的约束,则可以在建表后使用alter table命令为表增加约束。但是要注意:增加not null约束时,需要使用modify选项,而增加其它四种约束使用add选项。

  1. 增加商品名也不能为空
    SQL> alter table goods modify goodsName not null;
  2. 增加身份证也不能重复
    SQL> alter table customer add constraint xxxxxx unique(cardId);
  3. 增加客户的住址只能是’海淀’,’朝阳’,’东城’,’西城’,’通州’,’崇文’,’昌平’;
    SQL> alter table customer add constraint yyyyyy check (address in (’海淀’,’朝阳’,’东城’,’西城’,’通州’,’崇文’,’昌平’));

删除约束
当不再需要某个约束时,可以删除。
alter table 表名 drop constraint 约束名称;
特别说明一下:
在删除主键约束的时候,可能有错误,比如:
alter table 表名 drop primary key;
这是因为如果在两张表存在主从关系,那么在删除主表的主键约束时,必须带上cascade选项 如像:
alter table 表名 drop primary key cascade;

显示约束信息
1.显示约束信息
通过查询数据字典视图user_constraints,可以显示当前用户所有的约束的信息。
select constraint_name, constraint_type, status, validated from user_constraints where table_name = ‘表名’;
2.显示约束列
通过查询数据字典视图user_cons_columns,可以显示约束所对应的表列信息。
select column_name, position from user_cons_columns where constraint_name = ‘约束名’;
3.当然也有更容易的方法,直接用pl/sql developer查看即可。简单演示一下下…

表级定义 列级定义
列级定义
列级定义是在定义列的同时定义约束。
如果在department表定义主键约束
create table department4(dept_id number(12) constraint pk_department primary key,
name varchar2(12), loc varchar2(12));
表级定义
表级定义是指在定义了所有列后,再定义约束。这里需要注意:
not null约束只能在列级上定义。
外键:
以在建立employee2表时定义主键约束和外键约束为例:
create table employee2(emp_id number(4), name varchar2(15),
dept_id number(2), constraint pk_employee primary key (emp_id),
constraint fk_department foreign key (dept_id) references department4(dept_id));

18.oracle 序列(sequence)
需求:在某张表中,存在一个id列(整数),我们希望添加记录的时候,该列从1开始,自动的增长
解决方式:oracle是利用(sequence)来完成的
序列特点:由用户创建数据库对象,可由多个用户共享(system可以使用scott创建的序列),一般用于主键或唯一列,可为表中的列自动产生值。
问题:若system使用scott的序列,从什么开始增长? 答案:接着增长
insert into test1 values(scott.myseq.nextval,‘kkk’);
eg:创建一个序列:
create sequence myseq --创建开始
start with 1 --从1开始
increment by 1 --每次增长1
minvalue 1 --最小值
maxvalue 30000 --最大值
cycle //cycle表示当序列增加30000,重新从1开始,如果不希望,就nocycle
nocache; --不缓存,而 cache 10;表示一次产生10个号共你使用,缺点可能会跳号,但提供效率
使用序列创建一张表:
create table test1(id number primary key,name varchar2(32));
insert into test1 values(myseq.nextval,‘abc’);
insert into test1 values(myseq.nextval,‘dc’);
insert into test1 values(myseq.nextval,‘ac’);
insert into test1 values(myseq.nextval,‘ec’);
说明:myseq:表示序列名字,nextval:这是一个关键字,序列的一个函数
[序列不是在表定义中附加] 是在添加数据时使用
select scott.myseq.currval from dual; 查看当前序号

何时使用sequence:
不包含子查询、snapshot、view、select的语句中,经常使用在insert(子查询)、update语句中。

在sql server和mysql中都是可以在定义表的时候,直接给指定自增长:

19.oracle 索引
索引是用于加速数据存取的数据对象。合理的使用索引可以大大降低i/o次数,从而提高数据访问性能。索引有很多种我们主要介绍常用的几种:
为什么添加了索引后,会加快查询速度呢?

创建索引
单列索引
单列索引是基于单个列所建立的索引,比如:
create index 索引名 on 表名(列名);
复合索引
复合索引是基于两列或是多列的索引。在同一张表上可以有多个索引,但是要求列的组合必须不同,比如:
create index emp_idx1 on emp (ename, job);
create index emp_idx1 on emp (job, ename);

使用原则

  1. 在大表上建立索引才有意义
  2. 在where子句或是连接条件上经常引用的列上建立索引
  3. 索引的层次不要超过4层

索引的缺点
索引缺点分析
索引有一些先天不足:

  1. 建立索引,系统要占用大约为表1.2倍的硬盘和内存空间来保存索引。
  2. 更新数据的时候,系统必须要有额外的时间来同时对索引进行更新,以维持数据和索引的一致性。
    实践表明,不恰当的索引不但于事无补,反而会降低系统性能。因为大量的索引在进行插入、修改和删除操作时比没有索引花费更多的系统时间。

比如在如下字段建立索引应该是不恰当的:

  1. 很少或从不引用的字段;
  2. 逻辑型的字段,如男或女(是或否)等。
    综上所述,提高查询效率是以消耗一定的系统资源为代价的,索引不能盲目的建立,这是考验一个DBA是否优秀的很重要的指标。

其它索引
介绍
按照数据存储方式,可以分为B*树、反向索引、位图索引;
按照索引列的个数分类,可以分为单列索引、复合索引;
按照索引列值的唯一性,可以分为唯一索引和非唯一索引。
此外还有函数索引,全局索引,分区索引…

对于索引我还要说:
在不同的情况,我们会在不同的列上建立索引,甚至建立不同种类的索引,请记住,技术是死的,人是活的。比如:
B*树索引建立在重复值很少的列上,而位图索引则建立在重复值很多、不同值相对固定的列上。

显示索引信息
显示表的所有索引
在同一张表上可以有多个索引,通过查询数据字典视图dba_indexs和user_indexs,可以显示索引信息。其中dba_indexs用于显示数据库所有的索引信息,而user_indexs用于显示当前用户的索引信息:
select index_name, index_type from user_indexes where table_name = ‘表名’;
显示索引列
通过查询数据字典视图user_ind_columns,可以显示索引对应的列的信息
select table_name, column_name from user_ind_columns where index_name = ‘IND_ENAME’;
你也可以通过pl/sql developer工具查看索引信息

20.oracle管理权限和角色
这一部分我们主要看看oracle中如何管理权限和角色,权限和角色的区别在那里。
当刚刚建立用户时,用户没有任何权限,也不能执行任何操作。如果要执行某种特定的数据库操作,则必须为其授予系统的权限;如果用户要访问其它方案的对象,则必须为其授予对象的权限。为了简化权限的管理,可以使用角色。这里我们会详细的介绍。看图:

权限是指执行特定类型sql命令或是访问其它方案对象的权利,包括系统权限和对象权限两种。

系统权限是指执行特定类型sql命令的权利。它用于控制用户可以执行的一个或是一组数据库操作。比如当用户具有create table权限时,可以在其方案中建表,当用户具有create any table权限时,可以在任何方案中建表。oracle提供了100多种系统权限。
常用的有:
英文 中文 英文 中文
create session 连接数据库 create table 建表
create view 建视图 create public synonym 建同义词
create procedure 建过程、函数、包 create trigger 建触发器
create cluster 建簇

显示系统权限
oracle提供了100多种系统权限,而且oracle的版本越高,提供的系统权限就越多,我们可以查询数据字典视图system_privilege_map,可以显示所有系统权限。
select * from system_privilege_map order by name;

授予系统权限
一般情况,授予系统权限是由DBA完成的,如果用其他用户来授予系统权限,则要求该用户必须具有grant any privilege的系统权限。在授予系统权限时,可以带有with admin option选项,这样,被授予权限的用户或是角色还可以将该系统权限授予其它的用户或是角色。为了让大家快速理解,我们举例说明:
1.创建两个用户ken,tom。初始阶段他们没有任何权限,如果登录就会给出错误的信息。
create user ken identfied by ken;
2 给用户ken授权
1). grant create session, create table to ken with admin option;
2). grant create view to ken;
3 给用户tom授权
我们可以通过ken给tom授权,因为with admin option是加上的。当然也可以通过dba给tom授权,我们就用ken给tom授权:

  1. grant create session, create table to tom;
  2. grant create view to ken; --ok吗?不ok ,因为没有带上with admin option

回收系统权限
一般情况下,回收系统权限是dba来完成的,如果其它的用户来回收系统权限,要求该用户必须具有相应系统权限及转授系统权限的选项(with admin option)。回收系统权限使用revoke来完成。
当回收了系统权限后,用户就不能执行相应的操作了,但是请注意,系统权限级联收回的问题?[不是级联回收]
system --------->ken ---------->tom
(create session)(create session)( create session)
用system执行如下操作:
revoke create session from ken; --请思考tom还能登录吗?
答案:能,可以登录

对象权限
指访问其它方案对象的权利,用户可以直接访问自己方案的对象,但是如果要访问别的方案的对象,则必须具有对象的权限。 比如smith用户要访问scott.emp表(scott:方案,emp:表)
常用的有:
英文 中文 英文 中文
alter 修改 delete 删除
select 查询 insert 添加
update 修改 index 索引
references 引用 execute 执行

显示对象权限
通过数据字段视图可以显示用户或是角色所具有的对象权限。视图为dba_tab_privs
SQL> conn system/manager;
SQL> select distinct privilege from dba_tab_privs;
SQL> select grantor, owner, table_name, privilege from dba_tab_privs where grantee = ‘BLAKE’;

授予对象权限
在oracle9i前,授予对象权限是由对象的所有者来完成的,如果用其它的用户来操作,则需要用户具有相应的(with grant option)权限,从oracle9i开始,dba用户(sys,system)可以将任何对象上的对象权限授予其它用户。授予对象权限是用grant命令来完成的。
对象权限可以授予用户,角色,和public。在授予权限时,如果带有with grant option选项,则可以将该权限转授给其它用户。但是要注意with grant option选项不能被授予角色。
1.monkey用户要操作scott.emp表,则必须授予相应的对象权限
1). 希望monkey可以查询scott.emp表的数据,怎样操作?
grant select on emp to monkey;
2). 希望monkey可以修改scott.emp的表数据,怎样操作?
grant update on emp to monkey;
3). 希望monkey可以删除scott.emp的表数据,怎样操作?
grant delete on emp to monkey;
4). 有没有更加简单的方法,一次把所有权限赋给monkey?
grant all on emp to monkey;

2.能否对monkey访问权限更加精细控制。(授予列权限)
1). 希望monkey只可以修改scott.emp的表的sal字段,怎样操作?
grant update on emp(sal) to monkey
2).希望monkey只可以查询scott.emp的表的ename,sal数据,怎样操作?
grant select on emp(ename,sal) to monkey

3.授予alter权限
如果black用户要修改scott.emp表的结构,则必须授予alter对象权限
SQL> conn scott/tiger
SQL> grant alter on emp to blake;
当然也可以用system,sys来完成这件事。
4.授予execute权限
如果用户想要执行其它方案的包/过程/函数,则须有execute权限。
比如为了让ken可以执行包dbms_transaction,可以授予execute权限。
SQL> conn system/manager
SQL> grant execute on dbms_transaction to ken;
5.授予index权限
如果想在别的方案的表上建立索引,则必须具有index对象权限。
如果为了让black可以在scott.emp表上建立索引,就给其index的对象权限
SQL> conn scott/tiger
SQL> grant index on scott.emp to blake;
6.使用with grant option选项
该选项用于转授对象权限。但是该选项只能被授予用户,而不能授予角色
SQL> conn scott/tiger;
SQL> grant select on emp to blake with grant option;
SQL> conn black/shunping
SQL> grant select on scott.emp to jones;

回收对象权限
在oracle9i中收回对象的权限可以由对象的所有者来完成,也可以用dba用户(sys,system)来完成。
这里要说明的是:收回对象权限后,用户就不能执行相应的sql命令,但是要注意的是对象的权限是否会被级联收回?【级联回收】
如:scott------------->blake-------------->jones
select on emp select on emp select on emp
SQL> conn scott/tiger@accp
SQL> revoke select on emp from blake
请大家思考,jones能否查询scott.emp表数据。
答案:查不了了(和系统权限不一样,刚好相反)

最后总结:
系统权限 with admin option 回收时不级联回收
对象权限 with grant option 回收时级联回收

角色的管理:
一组权限的集合,目的是为了简化对权限的管理。
请看一个问题:假设有用户123,为了让他们拥有权限:
连接数据库,在scott.emp表上select,insert,update,如果采用直接授权,则需要12次授权。
解决办法:角色 解决具体方法见后面
角色的分类:
①预定义角色(33种)
常用的有(connect,dba,resource)
?查询某个角色具有哪些权限?//查询时名字一定要大写
SQL>select * from dba_sys_privs where grantee=‘DBA’;//查询时名字一定要大写
SQL>select * from dba_sys_privs where grantee=‘CONNECT’;
SQL>select * from dba_sys_privs where grantee=‘RESOURCE’;
system和sys是用户,但是可以如是查询:
?如何知道某个用户具有什么角色?
SQL>select * from dba_sys_privs where grantee=‘SYSTEM’;
SQL>select * from dba_sys_privs where grantee=‘SYS’;
SQL>select * from dba_sys_privs where grantee=‘XIAOQIANG’;
具有应用开发人员需要的大部分权限,只要给用于授予connect和resource权限即可。
需要注意的是:resource角色隐含了unlimited tablespace(表空间无限制),查询不出来。
案例:
创建一个用户,然后赋给connect角色:
create user aaa identified by m123;
grant connect to aaa;
DBA角色:具有所有的系统权限,with admin option选项,默认dba用户为sys和system他们可以将任何系统权限授予给其他用户,但是注意DBA不具备启动和关闭数据库。
案例:
创建一个用户,然后赋给DBA角色:
create user jack identified by m123;
grant dba to jack;

②自定义角色
oracle设计者,认为33种预定义角色可能不能满足所有需求,所以可以使用自定义角色。
建立角色(不验证):如果角色是公用的角色,可以采用不验证的方式建立角色(常用):
create role 角色名 not identified;
create role 角色名 identified by 密码;
案例:
请看一个问题:假设有用户123,为了让他们拥有权限:
连接数据库,在scott.emp表上select,insert,update,如果采用直接授权,则需要12次授权。
解决办法:
create role myrole not identified;
grant create session to myrole;
grant select on scott.emp to myrole;
grant insert on scott.emp to myrole;
grant update on scott.emp to myrole;
grant myrole to 123;

分配角色:
grant 角色名 to 用户名 [with admin option];
一般分配角色是由DBA(即sys/system)来完成的,若要求其他用户身份分配角色,则要求用户必须具有grant any role系统权限。
with admin option 授予权限的用户或是角色还可以将该系统权限授予其它的用户

删除角色:
drop role 角色名;(DBA来执行,其他用户要求具有drop any role系统权限)

21.PL/SQL
以下在scott/tiger账号下演示:
pl/sql(procedural language/sql):oracle在标准的sql语言上的扩展,允许使用条件和循环语句。
缺点:移植性不好,无法夸平台
优点:提供应用程序运行性能,模块化设计思想[分页过程,订单过程,转账过程],减少网络带宽,提供安全性
(1)存储过程简单版本
eg:开发一个简单的存储过程,可以完成向某表中添加一条记录:

块(编程):过程(存储过程)、函数、包(包体)、触发器。块是他们的基本编程单元。

编写规范
注释:单行注释–
多行注释/……/
表示符号的命名规范:

块(block)的开发
PL/SQL块由3个部分构成:定义部分、执行部分、例外处理部分

相关说明:dbms_output是oracle所提供的包(类似java),该包包含一些过程,put_line就是dbms_output包的一个过程。

特别说明:在默认情况下,“hello world”不输出,需要set serveroutput on;

将上面的块改为过程:

oracle只提示“未找到数据”,不准确,为此,我们加入exception异常处理机制:

对该案例的细节异常说明:

(2)存储过程升级版本

案例:请考虑编写一个过程,可以输入雇员名,新工资,可修改雇员的工资

(3)函数
eg:开发一个简单的存储过程,可以完成向某表中添加一条记录:

(4)包
使用包可以更好的管理 自己写的函数、过程
①包的规范只包含了过程和函数的说明,没有具体实现代码。

②包体用于实现包规范中的过程和函数。之前首先得建立包规范

在PL/SQL Developer下,用账号scott/tiger登录后
New—>Command Window—>然后在Edit窗口复制
上面命令,按F8运行,然后按/和Enter,后,出现
编译错误,请运行show error
运行:
exec mypackage1.pro5(‘KING’,12);

select scott.mypackage1.fun1(‘KING’) from dual;
最后总结:先声明包规范,再进行创建包体。

(5)触发器
触发器就是隐含的执行的存储过程,类似监听事件。定义触发器时要指定触发的事件和操作。
不是由程序员/DBA来显示调用,而是因为某个操作引发执行的。
常用触发器事件:insert/update/delete,实际就是一个PL/SQL块。
【提出问题】
①当用户登录时,自动记录该用户名字,登录时间,ip…
②当用户在星期天对某张表进行delete时,我们提示不能这样操作
③当用户删除某条记录的时候,自动将该记录保存到另外一张表去
【解决办法】触发器

触发器的分类
DM(数据操作语言,关于表中数据操作)L触发器:
DDL(数据定义语言,关于表的操作)触发器:
系统触发器(与胸相关的触发器,比如用户登录退出,关闭启动数据库)

使用条件谓词case…when和insert等词:

使用:old和:new
【提出问题】当触发器被触发时,要使用被插入、更新或删除的记录中的列值,有时要使用操作前、后列值

案例:
①在修改emp表雇员薪水时,显示雇员工资修改前和修改后的值
②如何确保修改员工工工资不能低于原有工资

案例:
编写一个触发器,保证当用户删除一张表(emp)记录的时候,自动把删除的记录备份到另外一张表(emp_bak)

案例:
编写一个触发器,如何控制员工薪水不能低于原来工资,同时也不能高出原来工资的20%,使用约束显然无法实现该规则。

系统触发器
(由DBA创建系统触发器) 一般由系统管理员来完成
系统时间指基于Oracle事件(startup,startdown等)所建立的触发器,通过使用系统事件触发器,提供了跟踪系统或数据库变化的机制。下面这个5个属性可以直接返回值,直接使用
ora_client_ip_address//返回客户端的ip
ora_database_name//返回数据库名
ora_login_user//返回登录用户名
ora_sysevent//返回触发器的系统事件名
ora_des_encrypted_password//返回用户des(md5)加密后的密码

案例:
记录用户的登录和退出事件,我们可以建立登录和退出触发器,为了记录用户名称,事件,ip地址,我们首先建立一张信息表。

DDL触发器
(对表定义删除的相关信息记录 需要DBA创建) 一般由系统管理员来完成

案例:

管理触发器
禁止触发器:让触发器临时失效
alter trigger 触发器名 disable;
激活触发器:
alter trigger 触发器名 enable;
禁止或激活触发表的所有触发器:
alter table emp disable all trigger;
alter table emp enable all trigger;
删除触发器:
drop trigger 触发器名;

PL/SQL语法数据类型
①标量类型(scalar)
名称 [constant] 数据类型 [not null] [:=初始值]
constant:指定常量,需要指定它的初始值,且其值是不能改变的
e.g:
定义一个变长字符串 v_ename varchar2(10)
定义一个小数 范围-9999.99-9999.99 v_sal number(6,2);
定义一个小数并给一个初始值5.4 v_sal number(6,2):=5.4 := 是pl/sql的赋值号
定义一个日期类型的数据 v_hiredate date;
定义一个布尔变量,不能为空初始值为false v_valid Boolean:=false

案例:以输入员工号,显示雇员姓名、工资、个人所得税(税率为0.03)

为了让v_ename类型更加灵活,我们使用%type v_ename emp.ename%type;
让我们在PL/SQL编程中,让变量类型和大小与表的列的大小和类型一致。
②复合类型(composite)

案例:请编写一个过程,该过程可以接受一个用户编号,并显示该用户名字,薪水,工作岗位

③参照类型(游标)(reference)
游标变量:通过游标,我们可以取得返回结果集(往往是select结果)的任何一行数据,从而提供共享的效率

(6)PL/SQL进阶控制结构
①条件分支语句
pl/sql中提供了三种条件分支语句:if——then if——then——else if——then——elsif——else
案例:编写一个过程,输入一个雇员,如果该雇员的补助不是0就在原来基础上增加100,如果补助为0就把补助设为200,空的话就设为150.

②循环语句loop|while|for
见PL/SQL语法数据类型–参照类型案例,可以进行循环插入记录利用存储过程

②goto|null
goto语句用于跳转到特定标号去执行语句,最好不要用。
null语句不会执行任何操作,只是提高代码可读性。

(7)PL/SQL进阶分页过程

(8)PL/SQL进阶例外

常见的几种例外:
例外情况名称 错误代码 描述
no_data_found ora-01403 对于select叙述没有传回任何值
too_many_rows ora_01427 只允许传回一笔记录的select叙述结果却多余一笔
invalid_cursor ora-01001 使用非法的光标操作
value_error ora-06502 出现数值、数据形态转换、截取字符串或强制性的错误
invalid_number ora-01722 字符串到数值的转换失败
zero_divide ora-01476 被零除
dup_val_on_index ora-00001 视图向具有唯一键值的索引中插入一个重复键值
case_not_found ora-06592 没有case条件匹配
cursor_not_open ora-06511 游标没有打开

(9)视图
oracle的又一种数据对象,虚拟表,视图的主要用处是简化操作,提高安全,满足不同用户查询需求,视图不是一个真正存在的物理表。它是根据别的表动态生成的。

22.数据库管理+表的逻辑备份与恢复
数据库管理员
每个oracle数据库应该至少有一个数据库管理员(dba),对于一个小的数据库,一个dba就够了,但是对于一个大的数据库可能需要多个dba分担不同的管理职责。那么一个数据库管理员的主要工作是什么呢:
职责
1.安装和升级oracle数据库
2.建库,表空间,表,视图,索引…
3.制定并实施备份和恢复计划
4.数据库权限管理,调优,故障排除
5.对于高级dba,要求能参与项目开发,会编写sql语句、存储过程、触发器、规则、约束、包
管理数据库的用户主要是sys和system
(sys好像是董事长,system好像是总经理,董事长比总经理大,但是通常是总经理干事)
在前面我们已经提到这两个用户,区别主要是:
1.最重要的区别,存储的数据的重要性不同
sys:所有oracle的数据字典的基表和视图都存放在sys用户中,这些基表和视图对于oracle的运行是至关重要的,由数据库自己维护,任何用户都不能手动更改。sys用户拥有dba,sysdba,sysoper角色或权限,是oracle权限最高的用户。
system:用于存放次一级的内部数据,如oracle的一些特性或工具的管理信息。system用户拥有dba,sysdba角色或系统权限。
sysdba角色可以建数据库,sysoper不能建数据库
2. 其次的区别,权限的不同。
sys用户必须以as sysdba或as sysoper形式登录。不能以normal方式登录数据库
system如果正常登录,它其实就是一个普通的dba用户,但是如果以as sysdba登录,其结果实际上它是作为sys用户登录的,从登录信息里面我们可以看出来。
sysdba和sysoper权限区别图,看图:

sysdba>sysoper>dba
可以看到:只要是sysoper拥有的权限,sysdba都有;蓝色是它们区别的地方。(它们的最大区别是:sysdba可以创建数据库,sysoper不可以创建数据库)

dba权限的用户
dba用户是指具有dba角色的数据库用户。特权用户可以执行启动实例,关闭实例等特殊操作,而dba用户只有在启动数据库后才能执行各种管理工作。(相当于说dba连startup和shutdown这两个权限都没有)
两个主要的用户,三个重要权限,他们的区别和联系,大家要弄清楚
管理初始化参数
管理初始化参数(调优的一个重要知识点,凭什么可以对数据库进行调优呢?是因为它可以对数据库的一些参数进行修改修正)
初始化参数用于设置实例或是数据库的特征。oracle9i提供了200多个初始化参数,并且每个初始化参数都有默认值。
显示初始化参数
(1) show parameter命令
如何修改参数
需要说明的如果你希望修改这些初始化的参数,可以到文件D:\oracle\admin\myoral\pfile\init.ora文件中去修改比如要修改实例的名字

数据库(表)的逻辑备份与恢复
介绍
逻辑备份是指使用工具export将数据对象的结构和数据导出到文件的过程,逻辑恢复是指当数据库对象被误操作而损坏后使用工具import利用备份的文件把数据对象导入到数据库的过程。
物理备份即可在数据库open的状态下进行也可在关闭数据库后进行,但是逻辑备份和恢复只能在open的状态下进行。
导出
导出具体的分为:导出表,导出方案,导出数据库三种方式。
导出使用exp命令来完成的,该命令常用的选项有:
userid: 用于指定执行导出操作的用户名,口令,连接字符串
tables: 用于指定执行导出操作的表
owner: 用于指定执行导出操作的方案
full=y: 用于指定执行导出操作的数据库
inctype: 用于指定执行导出操作的增量类型
rows: 用于指定执行导出操作是否要导出表中的数据
file: 用于指定导出文件名

导出表
1.导出自己的表
exp userid=scott/tiger@myoral tables=(emp,dept) file=d:\e1.dmp
2.导出其它方案的表
如果用户要导出其它方案的表,则需要dba的权限或是exp_full_database的权限,比如system就可以导出scott的表
E:\oracle\ora92\bin>exp userid=system/manager@myoral tables=(scott.emp) file=d:\e2.emp
特别说明:在导入和导出的时候,要到oracle目录的bin目录下。
3. 导出表的结构
exp userid=scott/tiger@accp tables=(emp) file=d:\e3.dmp rows=n
4. 使用直接导出方式
exp userid=scott/tiger@accp tables=(emp) file=d:\e4.dmp direct=y
这种方式比默认的常规方式速度要快,当数据量大时,可以考虑使用这样的方法。
这时需要数据库的字符集要与客户端字符集完全一致,否则会报错…

导出方案
导出方案是指使用export工具导出一个方案或是多个方案中的所有对象(表,索引,约束…)和数据。并存放到文件中。

  1. 导出自己的方案
    exp userid=scott/tiger@myorcl owner=scott file=d:\scott.dmp
  2. 导出其它方案
    如果用户要导出其它方案,则需要dba的权限或是exp_full_database的权限,比如system用户就可以导出任何方案
    exp userid=system/manager@myorcl owner=(system,scott) file=d:\system.dmp

导出数据库
导出数据库是指利用export导出所有数据库中的对象及数据,要求该用户具有dba的权限或者是exp_full_database权限
增量备份(好处是第一次备份后,第二次备份就快很多了)
exp userid=system/manager@myorcl full=y inctype=complete file=d:\all.dmp

导入
导入就是使用工具import将文件中的对象和数据导入到数据库中,但是导入要使用的文件必须是export所导出的文件。与导出相似,导入也分为导入表,导入方案,导入数据库三种方式。
imp常用的选项有
userid: 用于指定执行导入操作的用户名,口令,连接字符串
tables: 用于指定执行导入操作的表
formuser: 用于指定源用户
touser: 用于指定目标用户
file: 用于指定导入文件名
full=y: 用于指定执行导入整个文件
inctype: 用于指定执行导入操作的增量类型
rows: 指定是否要导入表行(数据)
ignore: 如果表存在,则只导入数据
导入表

  1. 导入自己的表
    imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp
  2. 导入表到其它用户
    要求该用户具有dba的权限,或是imp_full_database
    imp userid=system/tiger@myorcl tables=(emp) file=d:\xx.dmp touser=scott
  3. 导入表的结构
    只导入表的结构而不导入数据
    imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp rows=n
  4. 导入数据
    如果对象(如比表)已经存在可以只导入表的数据
    imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp ignore=y
    导入方案
    导入方案是指使用import工具将文件中的对象和数据导入到一个或是多个方案中。如果要导入其它方案,要求该用户具有dba的权限,或者imp_full_database
    1. 导入自身的方案
    imp userid=scott/tiger file=d:\xxx.dmp
    2. 导入其它方案
    要求该用户具有dba的权限
    imp userid=system/manager file=d:\xxx.dmp fromuser=system touser=scott
    导入数据库
    在默认情况下,当导入数据库时,会导入所有对象结构和数据,案例如下:
    imp userid=system/manager full=y file=d:\xxx.dmp

23.数据字典和动态性能视图
数据字典是oracle数据库中最重要的组成部分,它提供了数据库的一些系统信息。
动态性能视图记载了例程启动后的相关信息。

数据字典
数据字典记录了数据库的系统信息,它是只读表和视图的集合,数据字典的所有者为sys用户。
用户只能在数据字典上执行查询操作(select语句),而其维护和修改是由系统自动完成的。
这里我们谈谈数据字典的组成:数据字典包括数据字典基表和数据字典视图,其中基表存储数据库的基本信息,普通用户不能直接访问数据字典的基表。数据字典视图是基于数据字典基表所建立的视图,普通用户可以通过查询数据字典视图取得系统信息。数据字典视图主要包括user_xxx,all_xxx,dba_xxx三种类型。
user_tables;
用于显示当前用户所拥有的所有表,它只返回用户所对应方案的所有表
比如:select table_name from user_tables;
all_tables;
用于显示当前用户可以访问的所有表,它不仅会返回当前用户方案的所有表,还会返回当前用户可以访问的其它方案的表:
比如:select table_name from all_tables;
dba_tables;
它会显示所有方案拥有的数据库表。但是查询这种数据库字典视图,要求用户必须是dba角色或是有select any table系统权限。
例如:当用system用户查询数据字典视图dba_tables时,会返回system,sys,scott…方案所对应的数据库表。

用户名,权限,角色
在建立用户时,oracle会把用户的信息存放到数据字典中,当给用户授予权限或是角色时,oracle会将权限和角色的信息存放到数据字典。
通过查询dba_users可以显示所有数据库用户的详细信息;
通过查询数据字典视图dba_sys_privs,可以显示用户所具有的系统权限;
通过查询数据字典视图dba_tab_privs,可以显示用户具有的对象权限;
通过查询数据字典dba_col_privs可以显示用户具有的列权限;
通过查询数据库字典视图dba_role_privs可以显示用户所具有的角色。

这里给大家再讲讲角色和权限的关系。
例如:要查看scott具有的角色,可查询dba_role_privs;
SQL> select * from dba_role_privs where grantee=‘SCOTT’;

//查询orale中所有的系统权限,一般是dba
select * from system_privilege_map order by name;
//查询oracle中所有对象权限,一般是dba
select distinct privilege from dba_tab_privs;
//查询oracle中所有的角色,一般是dba
select * from dba_roles;
//查询数据库的表空间
select tablespace_name from dba_tablespaces;

问题1:如何查询一个角色包括的权限?
a.一个角色包含的系统权限
select * from dba_sys_privs where grantee=‘角色名’
另外也可以这样查看:
select * from role_sys_privs where role=‘角色名’
b.一个角色包含的对象权限
select * from dba_tab_privs where grantee=‘角色名’
问题2:oracle究竟有多少种角色?
SQL> select * from dba_roles;
问题3:如何查看某个用户,具有什么样的角色?
select * from dba_role_privs where grantee=‘用户名’

显示当前用户可以访问的所有数据字典视图。
select * from dict where comments like ‘%grant%’;
显示当前数据库的全称
select * from global_name;

其它说明
数据字典记录有oracle数据库的所有系统信息。通过查询数据字典可以取得以下系统信息:比如
1.对象定义情况
2.对象占用空间大小
3.列信息
4.约束信息

但是因为这些个信息,可以通过pl/sql developer工具查询得到,所以这里我就飘过。
动态性能视图
动态性能视图用于记录当前例程的活动信息,当启动oracle server时,系统会建立动态性能视图;当停止oracle server时,系统会删除动态性能视图。oracle的所有动态性能视图都是以v_开始的,并且oracle为每个动态性能视图都提供了相应的同义词,并且其同义词是以V开始的,并且oracle为每个动态性能视图都提供了相应的同义词,并且其同义词是以V开始的,并且oracle为每个动态性能视图都提供了相应的同义词,并且其同义词是以V开始的,例如v_datafile的同义词为vdatafile的同义词为vdatafile的同义词为vdatafile;动态性能视图的所有者为sys,一般情况下,由dba或是特权用户来查询动态性能视图。
因为这个在实际中用的较少,所以飞过。

24.oracle的卸载
一般的应用程序,安装后,可以通过uninstall工具来卸载,但是oracle没有,oracle卸载步骤如下:
1.先停止oracle的所有服务
2.使用Oracle universal installer(OUI)来完成初步卸载(该工具不会把oracle注册表信息清除,所以会把我们后续安装oracle或升级oracle带来麻烦)
3.到注册表中删除oracle的注册信息(regedit命令),删除下面内容:
①HKEY_LOCAL_MACHINE—>Software—>Oracle 删除此键
②HKEY_LOCAL_MACHINE—>System—> CurrentControlSet—>Services删除Services键下所有以oracle为首的键
③HKEY_LOCAL_MACHINE—>System—> CurrentControlSet—>Services—>Eventlog—>Application删除此键下的所有以oracle为首的键
④HKEY_CLASSES_ROOT删除此键下的所有以Ora、Oracle、EnumOra为前缀的键
⑤HKEY_CURRENT_USER—>Software—>Microsoft—>Windows—>CurrentVersion—>Explorer—>MenuOrder—>StartMenu—>Programs删除此键下的所有以Oracle为首的键
⑥HKEY_LOCAL_MACHINE—>Software—>ODBC—>ODBCINST.INI注册键,删除Microsoft ODBC FOR ORACLE注册表键以外的所有有Oracle字样的键值。
⑦HKEY_LOCAL_MACHINE—>System—>CurrentControlSet—>Services删除以Oracle或OraWeb为前缀的键
4.删除环境变量CLASSPATH,PATH中含有Oracle字样的值
5.最后再文件系统内删除ORACLE相关的文件及目录,删除系统盘符:\Program Files\Oracle目录;删除ORCLE_BASE目录
我无法删除D:\oracle目录,重新启动机器之后才删除
在默认情况下,oracle卸载并不会删除你的数据库文件,所以你手动删除出现错误,如果删除出现错误,则重启后再删除
25.尚学堂SQL简单讲解
desc emp 描述表信息
desc dept
desc salgrade
select ename,sal*12 as 年薪 from emp;
数据库中两个单引号来替代一个单引号
select ename || ‘adfa’‘s’ from emp;
||连接字符串
select distinct deptno,job from emp;

lower函数
chr(65) accii码转换成字符
ascii(A) 字符转换成accii码
round(23.54) 四舍五入
round(23.236,2) 四舍五入到小数点后面2位
round(23.236,-1) 四舍五入到十位数
在oracle中先将scott账户解锁,然后使用scott账户可以看到emp表
将$写成L,表示本地货币

nvl函数 如果comm为空就用0代替他 如果不是空置,就使用comm
组函数
通过to_char 小数点后两位
求部门个数

select from where 完整夫妻对分组进行限制 所以先分组后限制

Oracle常用函数
(1)trunc(for date)
这里注意 to_date date是日期值 所以转换后是不含有时间
TRUNC(for date) TRUNC函数为指定元素而截去的日期值。
  其具体的语法格式如下: TRUNC(date[,fmt])
  其中:date一个日期值,fmt日期格式,该日期将由指定的元素格式所截去。忽略它则由最近的日期截去
下面是该函数的使用情况:(mi minute 分钟的意思)
select trunc(to_date(‘2012-03-23 23:59:59’,‘yyyy-mm-dd hh24:mi:ss’)) from dual
系统定义表,只有一笔记录.可以用来返回函数值. select user from dual;返回当前用户. dual为了完善语义,因为没有from oracle中是报错的
– return date : 2012-3-23
trunc(sysdate,‘yyyy’) --返回当年第一天.
trunc(sysdate,‘mm’) --返回当月第一天.
trunc(sysdate,‘d’) --返回当前星期的第一天(如2012-07-11所在星期的第一天是2012-07-08)
思考:?如何获取当月的最后一天(提示:根据系统时间)?

(2)trunc(number)
  TRUNC函数返回处理后的数值,其工作机制与ROUND函数极为类似,只是该函数不对指定小数前或后的部分做相应舍入选择处理,而统统截去。
  其具体的语法格式如下TRUNC(number[,decimals])
  其中:number待做截取处理的数值,decimals指明需保留小数点后面的位数。可选项,忽略它则截去所有的小数部分
  下面是该函数的使用情况:
  TRUNC(89.985,2)=89.98
  TRUNC(89.985)=89
  TRUNC(89.985,-1)=80
  注意:第二个参数可以为负数,表示为小数点左边指定位数后面的部分截去,即均以0记。与取整类似,比如参数为1即取整到十分位,如果是-1,则是取整到十位,以此类推;如果所设置的参数为负数,且负数的位数大于整数的字节数的话,则返回为0。如:TRUNC(89.985,-3)=0.

(3)to_char
把日期或数字转换为字符串;to_date是把字符串转换为数据库中得日期类型
使用TO_CHAR函数处理数字:TO_CHAR(number, ‘格式’);TO_CHAR(salary,’$99,999.99’);
使用TO_CHAR函数处理日期: TO_CHAR(date,’格式’);

(4)to_date
使用TO_DATE函数将字符转换为日期:TO_DATE(char[, ‘格式’])
e.g select to_date(‘2011-11-5 4:39:57’,‘yyyy-mm-dd hh24:mi ss’) as col from dual

(5)to_number
使用TO_NUMBER函数将字符转换为数字:TO_NUMBER(char[, ‘格式’])
各种格式:
数字格式格式 日期格式
9代表一个数字
0强制显示0
放置一个放置一个放置一个符
L放置一个浮动 本地货币符
.显示小数点
,显示千位指示符
格式控制描述
YYYY、YYY、YY分别代表4位、3位、2位的数字年,YEAR年的拼写
MM数字月,MONTH月的全拼,MON月的缩写
DD数字日,DAY星期的全拼,DY星期的缩写,AM表示上午或者下午
HH24、HH12 12小时制或24小时制,MI分钟,SS秒钟
SP数字的拼写,TH数字的序数词
“特殊字符”假如特殊字符
HH24:MI:SS AM 15:43:20 PM
DD “OF” MONTH 12 OF OCTOBER
DDSPTH fourteenth
Date的格式 ’18-5月-84’

(6)instr
INSTR方法的格式为:INSTR(源字符串,目标字符串,起始位置,匹配序号)
查询是否匹配目标字符串
例如:INSTR(‘CORPORATE FLOOR’,‘OR’, 3, 2)中,源字符串为’CORPORATE FLOOR’,目标字符串为’OR’,起始位置为3,取第2个匹配项的位置。
默认查找顺序为从左到右。当起始位置为负数的时候,从右边开始查找。
所以SELECT INSTR(‘CORPORATE FLOOR’, ‘OR’, -1, 1) “Instring” FROM DUAL的显示结果是:14
别名Instring

(7)substr
取得字符串中指定起始位置和长度的字符串substr( string, start_position, [ length ] )
如:
substr(‘This is a test’, 6, 2) return ‘is’
substr(‘This is a test’, 6) return ‘is a test’
substr(‘TechOnTheNet’, -3, 3) return ‘Net’
substr(‘TechOnTheNet’, -6, 3) return 'The’select substr(‘Thisisatest’, -4, 2) value from dual
举个例子更容易区分这两个函数:

(8)trim
Oracle中的trim函数是用来删除给定字符串或者给定数字中的头部或者尾部的给定字符。
trim函数具有如下的形式trim([leading/trailing/both][匹配字符串或数值][from][需要被处理的字符串或数值])这里如果
① 指明了leading表示从删除头部匹配的字符串
② 如果指明了trailing表示从删除尾部匹配的字符串
③ 如果指明了both,或者不指明任何位置,则两端都将被删除
④如果不指明任何匹配字符串或数值则认为是空格,即删除前面或者后面的空格。
trim函数返回的类型是varchar2下面是一些例子:
各种情况 例子 结果
指明leading表示从删除头部匹配的字符串 select trim(leading ‘1’ from ‘12321Tech11’) from dual; 2321Tech11
指明trailing表示从删除尾部匹配的字符串 select trim(trailing ‘1’ from ‘12321Tech11’) from dual; 12321Tech
如果指明了both,或者不指明任何位置,则两端都将被删除 select trim(‘中’from‘中秋八月中‘) as诗from dual;
select trim(both ‘1’ from ‘12321Tech 111’) from dual;
秋八月
2321Tech
如果不指明任何匹配字符串或数值则认为是空格,即删除前面或者后面的空格 select trim(’ tech ‘) as诗from dual;
select trim(’ ’ from ’ tech ‘) as诗from dual;
select trim(0 from 7500) from dual; tech
tech
75
LTRIM, RTRIM 不但可以去掉空格,还可以去掉指定字符, 如LTRIM(’,aaaa’,‘,’)
ltrim rtrim

(9)translate
语法:TRANSLATE(char, from, to)
用法:返回将出现在from中的每个字符替换为to中的相应字符以后的字符串。
若from比to字符串长,那么在from中比to中多出的字符将会被删除。
三个参数中有一个是空,返回值也将是空值。
举例:SQL> select translate(‘abcdefga’,‘abc’,‘wo’)返回值from dual;
返回值------- wodefgw
分析:该语句要将’abcdefga’中的’abc’转换为’wo’,
由于’abc’中’a’对应’wo’中的’w’,故将’abcdefga’中的’a’全部转换成’w’;
而’abc’中’b’对应’wo’中的’o’,故将’abcdefga’中的’b’全部转换成’o’;
而’abc’中的’c’在’wo’中没有与之对应的字符,故将’abcdefga’中的’c’全部删除;
简单说来,就是将from中的字符转换为to中与之位置对应的字符,若to中找不到与之对应的字符,返回值中的该字符将会被删除。
在实际的业务中,可以用来删除一些异常数据,比如表a中的一个字段t_no表示电话号码,而电话号码本身应该是一个由数字组成的字符串,
为了删除那些含有非数字的异常数据,就用到了translate函数:
SQL> delete from a, where length(translate(trim(a.t_no), ‘0123456789’ || a.t_no, ‘0123456789’)) <> length(trim(a.t_no));

(10)replace
语法:REPLACE(char, search_string,replacement_string)
用法:将char中的字符串search_string全部转换为字符串replacement_string,没有匹配的字符串就都不变。
举例:
SQL> select REPLACE(‘fgsgswsgs’, ‘fk’ ,‘j’) from dual;返回值from dual;
结果是fgsgswsgs
SQL> select REPLACE(‘fgsgswsgs’, ‘sg’ ,‘eeerrrttt’)返回值from dual;
结果是fgeeerrrtttsweeerrrttts
分析:第一个例子中由于’fgsgswsgs’中没有与’fk’匹配的字符串,故返回值仍然是’fgsgswsgs’;
第二个例子中将’fgsgswsgs’中的字符串’sg’全部转换为’eeerrrttt’。
总结:综上所述,replace与translate都是替代函数,只不过replace针对的是字符串,而translate针对的是单个字符。

(11)decode()
DECODE函数,它将输入数值与函数中的参数列表相比较,根据输入值返回一个对应值。函数的参数列表是由若干数值及其对应结果值组成的若干序偶形式。当然,如果未能与任何一个实参序偶匹配成功,则函数也有默认的返回值。
区别于SQL的其它函数,DECODE函数还能识别和操作空值。
语法:DECODE(control_value,value1,result1[,value2,result2…][,default_result]);
试图处理的数值。DECODE函数将该数值与后面的一系列的偶序相比较,以决定返回值。
value1 是一组成序偶的数值。如果输入数值与之匹配成功,则相应的结果将被返回。对应一个空的返回值,可以使用关键字NULL于之对应。
result1 是一组成序偶的结果值。
default_result 未能与任何一个值匹配时,函数返回的默认值。
例如:
select decode(x,1,‘x is 1’,2,‘x is 2’,‘others’) from dual
当x等于1时,则返回‘x is 1’。
当x等于2时,则返回‘x is 2’。
否则,返回others’。
需要,比较2个值的时候,可以配合sign()函数一起使用。
SELECT DECODE( SIGN(5-6), 1 ‘Is Positive’, -1, ‘Is Nagative’, ‘Is Zero’)from dual;
同样,也可以用CASE实现:
SELECT CASE SIGN(5-6)
WHEN 1 THEN ‘Is Positive’
WHEN -1 THEN ‘Is Nagative’
ELSE ‘Is Zero’ END
FROM DUAL
此外,还可以在Order by中使用Decode。
例如:表subject,有subject_name列。要求按照:语、数、外的顺序进行排序。这时,就可以非常轻松的使用Decode完成要求了。
select * from subject order by decode(subject_name, ‘语文’,1, ‘数学’,2, ‘外语’,3)
(12)nvl
nvl( ) 函数(类似于SQLSERVER的isnull)
语法: 1. NVL(eExpression1, eExpression2)
参数: 1. eExpression1, eExpression2
如果eExpression1的计算结果为null值,则NVL( )返回eExpression2。
如果eExpression1的计算结果不是null值,则返回eExpression1。
eExpression1和eExpression2可以是任意一种数据类型。
如果eExpression1与eExpression2的结果皆为null值,则NVL( )返回.NULL.。

  1. select nvl(a.name,‘空得’) as name from student a join school b on a.ID=b.ID
    注意:两个参数得类型要匹配
    一、Oracle安装
    1、Oracle在真正使用的时候都是装在Linux系统下。

2、Oracle并没有官方明确声明支持Ubuntu系统,所以尽量装在redhat等linux系统上。

3、mysql的默认端口是3306,Oracle的默认端口是1521。如果数据库使用的端口不是默认端口,可以使用360安全卫士或者Fport(不支持win7系统)查看真正占用的端口。

4、Oracle 10g无法安装到win7,如果使用的是win7系统,可以安装Oracle 11g。

5、如果使用的win7系统,并且想要安装Oracle 10g,可以将其安装到虚拟机上。这样,也便于卸载。

6、Oracle 11g有两个包,将两个包都装上,功能才是最全的。(具体安装流程请参考安装文档)

7、Oracle安装过程中的任何路径都不能出现中文、空格以及特殊字符。

8、设置虚拟机的网络连接方式的时候,如果设置桥接网卡,则意味着虚拟机和宿主机处于一个局域网中。如果在Linux系统中,则可以设置为Host-only,此时其IP为192.168.56.101。

9、安装Oracle的时候,解锁两个账户,分别是SCOTT和HR,SCOTT的密码默认为tiger,HR的密码默认为HR。

10、通过sqlplus scott/tiger测试是否安装成功。

二、Oracle Database
1、连接Oracle数据库的时候,可以使用两个url:jdbc:oracle:thin:@localhost:1521:orcl以及jdbc:oracle:oci:@localhost:1521:orcl。两个区别在于后者需要安装Oracle客户端,并且性能上后者大于前者。(如果是Oracle集群,必须安装客户端。)

2、Oracle SQL Developer不需要安装Oracle客户机,PL/SQL Developer则必须安装Oracle客户机。

3、一个Oracle服务器是一个数据库管理系统(RDBMS),它提供开放的,全面的,近乎完整的信息管理。它有多个Oracle实例以及一个Oracle数据库组成。

4、Oracle数据库:位于硬盘上实际存放数据的文件,这些文件组织在一起,成为一个逻辑整体,即为Oracle数据库。因此在Oracle看来,“数据库”是指硬盘上文件的逻辑集合,必须要与内存里实例合作,才能对外提供数据管理服务。

5、Oracle实例:位于物理内存里的数据结构。它由一个共享的内存池和多个后台进程所组成,共享的内存池可以被所有进程访问。用户如果要存取数据库(也就是硬盘上的文件)里的数据,必须通过实例才能实现,不能直接读取硬盘上的文件。

6、Oracle数据库与Oracle实例的区别:实例可以操作数据库;在任何时刻一个实例只能与一个数据库关联;大多数情况下,一个数据库上只有一个实例对其进行操作。

7、集群的概念

如果只有一个Oracle实例操纵一个Oracle数据库,那么如果一旦连接断了,那么就无法对数据库进行操作了。所以需要引入集群的概念,也就是说通过多个Oracle实例操作Oracle数据库可以达到失败迁移的效果,也就是一个Oracle实例B不能对Oracle数据库进行操作,还可以有另一个Oracle实例C对Oracle数据库进行操作,并且可以实现负载均衡。

在WEB应用中,同样存在集群的概念。也就是当多个tomcat服务器上部署的多个WEB应用操作MYSQL数据库的时候,如果一个tomcat服务器挂掉了,另外一个tomcat服务器能够照常对MYSQL数据库进行操作。

8、Oracle数据库的结构

在一个Oracle实例中,使用JDBC对数据库操作的时候,首先请求会存放在PGA(Process Global Area)中,然后所有的PGA中的请求都会存放在SGA(System Global Area)中。然后通过读、写进程等后台进程操作数据库。这样就可以在SGA调用后台程序执行前进行闪回操作。

9、进程和线程的区别
进程是一个操作系统概念,线程是一个程序概念。

10、表空间为逻辑概念,数据文件为物理概念。表空间是多个数据文件(DBF)组成,数据文件只能属于一个表空间。用户只能操作表空间为users的表空间。

11、数据库的逻辑和物理结构:

一个数据库包含多个表空间。表空间包含多个段,段是区的集合,区是数据块的集合,数据块会被映射到磁盘块。

12、Oracle数据库是一个庞大的软件,启动它会占用大量的内存和CPU资源,如果不想让Oracle数据库自动启动,则可以设置为手动启动。

13、Oracle Database客户机就是要从局域网内的一台计算机上访问另一台计算机上的Oracle服务,需要在此计算机上安装能通过局域网访问另一台计算机上的Oracle服务的客户机。

14、数据库用户管理
①管理员登陆
sqlplus sys/*** as sysdba;
sqlplus / as sysdba;
②解锁
alter user scott account unlock;
③改密码
alter user scott identified by 新密码;
三、基本SQL Select语句
1、通过spool c:\select语句.txt、spool off记录sql语句日志。

2、show user --显示当前操作用户名。

3、select * from tab; --显示当前用户下的表。

4、desc emp --显示表结构

5、set linesize 120 --设置行宽
col ename for a8 --设置列宽,a表示字符,设置字符列为8位
col sal for 9999 --设置数字格式为四位

6、select * from emp; --查询所有员工的所有信息

7、/ --执行上条执行的指令

8、select empno,ename,job,mgr,hierdate,sal,comm,deptno from emp; --通过列名查询

9、修改错误的sql语句。

在使用c命令修改前,首先应该指出修改第几行,例如上面的2表示修改第2行,然后通过 c/fomr/from表示将fomr修改为from。然后通过“/”执行已经修改正确的指令。

10、select empno,ename,sal,sal12 年薪,comm 奖金,sal12+comm 年收入 from emp; --使用别名做列名,可以直接使用别名,或通过as关键字。

注:别名中如果包含空格或特殊的字符,则必须加上双引号。
别名区分大小写。
使用别名便于计算。

11、通过ed命令可以使用文本编辑器修改sql语句。

12、空值是无效的,未指定的,未知的或不可预知的值。空值不是空格或者0。SQL中包含null值的表达式都为null,并且null!=null。此时,可以通过滤空函数(nvl)来解决。

13、查询奖金为null的员工,注意不能使用comm=null作为查询条件,而应该使用comm is null作为查询条件。

14、使用DISTINCT去掉重复记录。

DISTINCT作用于后面所有的列。如果后面有多个列,那么必须多列数据都相同才算做重复记录。

15、select * from departments; --选择全部列。

16、注意:
SQL语言大小写不敏感。
SQL可以写在一行或者多行。
关键字不能被缩写也不能分行。
各子句一般要分行写。
使用缩进提高语句的可读性。

17、算数运算符
乘除的优先级高于加减。
优先级相同时,按照从左至右运算。
可以使用括号改变优先级。
例子:select last_name,salary,12*(sal+100) from employee;

18、连接符
把列与列,列与字符连接在一起。用“||”表示,可以用来“合成”列。

连接符作用与concat方法一致。

19、伪表

20、字符串
字符串可以是select列表中的一个字符,数字,日期。
日期和字符只能在单引号中出现。
例子:select last_name||’ is a '||job_id as “Employee Details” from employees;

21、保存sql语句到文件中,并且通过“@”调用sql文件,执行sql语句。

SQL优化
SQL优化:
1、尽量使用列名(Oracle9i之后,和列名一样)。
2、尽量使用where。在分组数据中可以使用having作为过滤条件,也可以使用where语句。使用where效率更高。
3、使用order by进行排序。
四、SQL和SQL
Plus
1、SQL语句与SQL*Plus命令

SQL是一种语言,ANSI标准,关键字不能缩写,并且使用语句控制数据库中的表的定义信息和表中的数据。
SQLPlus是一种环境,Oracle的特性之一,关键字可以缩写,命令不能改变数据库中的数据的值,并且是集中运行。
SQL
Plus常用命令及其全称。
desc–>describe
set–>set
col–>column
c–>change
ed–>edit

2、iSQLPlus
使用iSQL
Plus可以:
描述表结构。
编辑SQL语句。
执行SQL语句。
将SQL保存在文件中并将SQL语句执行结果保存在文件中。
将文本文件装入SQL*Plus编辑窗口。
例如:http://localhost:5560/isqlplus/

3、Oracle EM(Enterprise Manager)的端口为1158。

五、过滤和排序数据
1、使用where子句,将不满足条件的行过滤掉。
例子:查询10号部门的员工。

2、字符和日期
字符和日期要包含在单引号中。
字符大小写敏感,日期格式敏感。
默认的日期格式是DD-MON-RR。

3、比较运算
=、>、>=、<、<=、<>(也可以是!=)。
BETWEEN…AND… 在两个值之间(包含边界)

注:小值在前,大值在后。

IN(set) 等于值列表中的一个

LIKE 模糊查询(%表示0个或多个任意字符,_表示一个任意字符)

如果用户名中必须包含‘_’字符,则需要转义。

注意:可以使用括号改变优先级顺序。

4、ORDER BY子句
使用ORDER BY子句排序。ASC(ascend):升序,DESC(descend):降序

注:直接使用列序号也能进行排序。

注:如果使用多列进行排序,那么首先按照第一列进行排序,然后在按照第二列进行排序,以此类推。

由上图可以看到如果按照正序排序,那么列值为空值的行将排在后面。

通过a命令可以追加命令信息。

由上图可以看到如果按照逆序排序,那么列值为空值的行将排在上面。

为了实现列值为空值的行在逆序排序的情况下仍然排在下面,则只需要追加“nulls last”即可。
六、单行函数
1、单行函数与多行函数
(函数可以没有参数,但必须要有返回值)

单行函数用来操作数据对象,并且接受参数返回一个结果,只对一行进行变换,每行返回一个结果。它可以转换数据类型,也可以嵌套,并且参数可以是一列或一个值。

2、字符函数

注:通过上面的大小写函数可以解决一些字符比较问题。例如,名字可能有大写也可能有小写,则可以统一写成小写进行比较。
select employee_id,last_name,department_id from employees where LOWER(last_name)=‘higgins’;

3、数字函数
ROUND:四舍五入

TRUNC:截断

MOD:求余
select last_name,salary,MOD(salary,5000) from employees where job_id=‘SA_REP’;

4、日期
Oracle中的日期型数据实际含有两个值:日期和事件。
默认的日期格式是DD-MON-RR。

sysdate与systimestamp的区别都是返回数据库的时间并且使用数据库的时区,它们返回的是操作系统的时间。sysdate返回的是date类型,没有时区信息。systimestamp返回的有时区信息。

日期的数学函数
在日期上加上或减去一个数字结果仍为日期。
两个日期相减返回日期之间相差的天数。
可以用数字除24来向日期中加上或减去小时。

日期函数
MONTHS_BETWEEN 两个日期相差的月数
ADD_MONTHS 向指定日期中加上若干月数
NEXT_DAY 指定日期的下一个日期
LAST_DAY 本月的最后一天
ROUND 日期四舍五入
TRUNC 日期截断

5、转换函数

隐式数据类型转换(自动类型转换)

显示数据类型转换

TO_CHAR 函数对日期的转换
必须包含在单引号中而且大小写敏感。
可以包含任意的有效的日期格式。
日期之间用逗号隔开。

TO_CHAR 函数对日期的转换
下面是在TO_CHAR函数中经常使用的几种格式:

日期格式的元素

6、通用函数
这些函数适用于任何数据类型,同时也适用于空值。
NVL2

注:NVL与NVL2的区别在于,NVL(a,b),如果a为NULL,则NVL函数返回b值,否则返回a值。NVL2(a,b,c),如果a为NULL,则NVL2函数返回c值,否则返回b值。

NULLIF

COALESCE(从左往右找到第一个不为NULL的值)

7、条件表达式
CASE表达式:

DECODE函数:

8、嵌套函数
单行函数可以嵌套。
嵌套函数的执行顺序是由内到外。
七、分组函数
1、什么是分组函数?
分组函数作用于一组数据,并对一组数据返回一个值。

2、组函数类型
SUM

AVG

COUNT

注:
1、由上两图可以看到所有的组函数都会自动滤空。解决方案可以通过NVL函数解决。
例如:select SUM(NVL(comm,0))/COUNT(NVL(comm,0)) from emp;
2、通过DISTINCT关键字返回表达式非空且不重复的记录总数。
select COUNT(DISTINCT department_id) from employees;

MAX
MIN

3、分组数据:GROUP BY子句
可以使用GROUP BY子句将表中的数据分成若干组。

注:
1、在SELECT列表中所有未包含在组函数中的列都应该包含在GROUP BY子句中。
select department_id,AVG(salary) from employees group by department_id;
2、包含在GROUP BY子句中的列不必包含在select列表中。
select AVG(salary) from employees group by department_id;

4、过滤分组:HAVING子句
1、行已经被分组。
2、使用了组函数。
3、满足HAVING子句中条件的分组将被显示。

注:可以看到在分组数据中可以使用having作为过滤条件,也可以使用where语句。由于使用where效率更高,所以能使用where语句的就不少使用having作为过滤条件。但是,having与where不同之处在于可以使用分组函数。

5、GROUP BY语句的增强
问题:按照部门统计各部门不同工种的工资情况,要求按如下格式输出:

注:同上图可以看到,为了实现问题中的效果,应该先组织好数据,然后通过break on deptno skip 2调整格式。最后,如果想要消除效果,则再通过break on null完成。
八、笛卡尔积与连接类型
1、笛卡尔积
①笛卡尔积会在下面条件下产生:
省略连接条件
连接条件无效
所有表中的所有行互相连接
②为了避免笛卡尔积,可以在where语句中加入有效的连接条件。
③在实际运行环境下,应避免使用全笛卡尔积。

2、连接的类型
等值连接

不等值连接

外连接

自连接

3、层次查询

九、子查询
1、子查询
子查询(内查询)在主查询之前一次执行完成。子查询的结果被组查询使用(外查询)。
例子:查询出比SCOTT工资多的雇员的信息。

2、注意的问题
①括号。

②采用合理的书写风格。

③可以主查询的where from select having后面放置子查询。

④不可以主查询的group by后面放置子查询。

⑤单独强调from后面放置的子查询。

⑥主查询和子查询可以不是同一张表,只要子查询返回的结果,主查询可以使用即可。

上图的功能用多表查询也可以实现。

⑦一般不在子查询中,不使用order by;但在Top-N分析问题中,必须使用order by。

⑧一般先执行子查询,再执行主查询;但相关子查询除外。

⑨单行子查询只能使用单行操作符;多行子查询只能使用多行操作符。
单行子查询只返回一行,使用单行比较操作符(=、>、>=、<、<=、<>)。
例子:select last_name,job_id,salary from employees where job_id=(
select job_id from employees where employee_id=141
) and salary>(
select salary from employees where employee_id=143
);

多行子查询,返回多行。使用多行比较操作符(IN、ANY、ALL)。

在子查询中使用组函数。
select last_name,job_id,salary from employees where salary=(
select MIN(salary) from employees
);

子查询中的HAVING子句。
select department_id,MIN(salary) from employees group by department_id having MIN(salary)>(
select MIN(salary) from employees where department_id = 50
);

⑩子查询中的null。
select last_name,job_id from employees where job_id=(
select job_id from employees where last_name=‘Haas’
);
子查询中包含null值,则子查询不返回任何行。
例如:

由于上面的select mgr from emp子查询语句包含NULL,所以不返回任何行。因为IN操作符相当于<>ANY,也就是AND逻辑。
例如:a not in (10,20,null)相当于a!=10 and a!= 20 and a!=null。
此时,在进行子查询的时候应当将为null的值的行数据过滤掉。

3、rownum 行号(伪列)

注:1、rownum永远按照默认的顺序生成。
2、rownum只能使用<、<=,不能使用>、>=。

4、课堂练习
①找到员工表中工资最高的前三名,如下格式:

答案:

②找到员工表中薪水大于本部门平均薪水的员工。

答案:

③统计每年入职的员工个数。

答案:

十、集合运算
1、集合运算符

UNION/UNION ALL 并集

INTERSECT 交集
显示薪水同时位于级别1(7001300)和级别2(12011400)的员工信息。
select ename,sal from emp where sal between 700 and 1300
INTERSECT
select ename,sal from emp where sal between 1201 and 1400;

MINUS 差集
显示薪水同时位于级别1(7001300),但不属于级别2(12011400)的员工信息。
select ename,sal from emp where sal between 700 and 1300
MINUS
select ename,sal from emp where sal between 1201 and 1400;
十一、处理数据
1、处理数据的SQL语句

2、INSERT
使用INSERT语句向表中插入数据。

向表中插入空值。
隐式方式:在列名表中省略该列的值。
INSERT INTO departments VALUES(department_id,department_name) values(30,‘Purchasing’);
显示方式:在values子句中指定空值。
INSERT INTO departments VALUES(100,‘Finance’,NULL,NULL);

插入指定的值。
INSERT INTO employees VALUES(114,‘Den’,‘Raphealy’,‘DRAPHEAL’,‘515.127.4561’,TO_DATE(‘FEB 3,1999’,‘MON DD,YYYY’),‘AC_ACCOUNT’,11000,NULL,100,30);

3、创建脚本
在SQL语句中使用&变量指定列值。&变量放在VALUES子句中。

4、批处理:一次插入多条数据

在其他表中拷贝数据。
·在INSERT语句中加入子查询。
·不必书写VALUES子句。
·子查询中的值列表应与INSERT子句中的列名对应。

5、UPDATE
使用update语句更新数据。
UPDATE employees SET department_id=70 WHERE employee_id=113;
可以一次更新多条数据。
UPDATE copy_emp SET department_id=110;

在UPDATE语句中使用子查询
在UPDATE中使用子查询,使更新基于另一个表中的数据。
UPDATE copy_emp SET department_id=(
SELECT department_id FROM employees WHERE employee_id=100
) WHERE job_id=(
SELECT job_id FROM employees WHERE employee_id = 200
);

6、DELETE
使用DELETE语句从表中删除数据。

7、数据库事务
数据库事务由以下的部分组成:
一个或多个DML语句
一个DDL(数据定义语言)语句
一个DCL(数据控制语言)语句

8、数据库的隔离级别
数据库提供的4种事务隔离级别:
READ UNCOMMITTED(读未提交数据)
允许事务读取未被其他事物提交的变更、脏读、不可重复读和幻读的问题都会出现。
READ COMMITTED(读已提交数据)
只允许事务读取已经被其它事务提交的变更。可以避免脏读,但不可重复读和幻读问题仍然可能出现。
REPEATABLE READ(可重复读)
确保事务可以多次从一个字段中读取相同的值。在这个事务持续期间,禁止其他事务对这个字段进行更新。可以避免脏读和不可重复读,但幻读的问题仍然存在。
SERIALIZABLE(串行化)
确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入,更新和删除操作。所有并发问题都可以避免,但性能十分低下。

Oracle支持的2种事务隔离级别:READ COMMITTED,SERIALIZABLE。Oracle默认的事务隔离级别为:READ COMMITTED。

Mysql支持4种事务隔离界别。Mysql默认的事务隔离级别为:REPEATABLE READ。
十二、DDL语句
1、表名和列名的命名规则
必须以字母开头。
必须在1-30个字符之间。
必须只能包含A-Z,a-z,0-9,_,$,和#。
必须不能和用户定义的其他对象重名。
必须不能使Oracle的保留字。
Oracle默认存储是都存为大写。
数据库名只能是1~8位,datalink可以是128位,和其他一些特殊字符。

2、数据类型

3、常用的数据库对象

4、CREATE TABLE
必须指定:表名,列名,数据类型,数据类型的大小。

查询其他用户的表。
其他用户的表不属于本用户的空间。
如果要查询其他用户下的表,要使用其他用户的用户名作为前缀。

使用子查询创建表
·使用As subquery选项,将创建表和插入数据结合起来。
·指定的列和子查询中的列要一一对应。
·通过列名和默认值定义列。

5、rowid 行地址

6、ALTER TABLE语句
·追加新的列
·修改现有的列
·删除一个列

7、删除表
·数据和结构都被删除
·所有正在运行的相关事务被提交
·所有相关索引被删除
·DROP TABLE语句不能回滚,但是可以闪回

注:管理员没有回收站。

8、改变对象的名称
·执行RENAME语句改变表,视图,序列,或同义词的名称。
RENAME dept TO detail_dept;
·必须是对象的拥有者

9、约束
·约束是表一级的限制
·如果存在依赖关系,约束可以防止错误的删除数据。
·约束的类型
①NOT NULL
②UNIQUE
③PRIMARY KEY

④CHECK
·定义每一行记录锁必须满足的条件。
·下面的表达式可以使用在check约束中:
·引用CURRVAL,NEXTVAL,LEVEL,和ROWNUM
·调用SYSDATE,UID,USER和USERENV函数
·另一个表的查询记录

⑤FOREIGN KEY
FOREIGN KEY:在子表中,定义了一个表级的约束。
REFERENCES:指定表和父表中的列。
ON DELETE CASCADE:当删除父表时,级联删除子表记录。
ON DELETE SET NULL:将子表的相关依赖记录的外键设置为null

十三、其他数据库对象
1、创建视图
·使用下面的语法格式创建视图
CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view
[(alias)[,alias]…]
As subquery
[WITH CHECK OPTION [CONSTRAINT constraint]]
[WITH READ ONLY [CONSTRAINT constraint]]
·FORCE:子查询不一定存在
·NOFORCE:子查询存在(默认)
·WITH READ ONLY:只能做查询操作
·子查询可以是复杂的SELECT语句

·创建视图时在子查询中给列定义别名
·在选择视图中的列时应使用别名

注:如果某个用户没有创建视图的权限,那么就需要先给这个用户赋权限。

·视图是一种虚表。
·视图建立在已有表的基础上,视图赖以建立的这些表成为基表。
·向视图提供数据内容的语句为SELECT语句,可以将视图理解为存储起来的SELECT语句。
·视图向用户提供基表数据的另一种表现形式。
·可以使用WITH READ ONLY选项屏蔽对视图的DML操作。
·任何DML操作都会返回一个Oracle Server错误。

2、简单视图和复杂视图

注:不建议通过视图对表进行修改。

3、修改视图
·使用CREATE OR REPLACE VIEW子句修改视图
·CREATE VIEW子句中各列的别名应和子查询中各列相对应。

注:建议不要对视图进行DML操作,例如delete、update、insert。

4、删除视图
删除视图只是删除视图的定义,并不会删除基表的数据。
DROP VIEW view;

5、什么是序列?
序列:可供多个用户用来产生唯一数值的数据库对象。
·自动提供唯一的数值
·共享对象
·主要用于提供主键值
·将序列值装入内存可以提高访问效率

6、CREATE SEQUENCE语句
定义序列:
CREATE SEQUENCE sequence
[INCREMENT BY n]
[START WITH n]
[{MAXVALUE n|NOMAXVALUE}]
[{MINVALUE n|NOMINVALUE}]
[{CYCLE|NOCYCLE}]
[{CACHE n|NOCACHE}];

7、NEXTVAL和CURRVAL伪列
·NEXTVAL返回序列中下一个有效的值,任何用户都可以引用。
·CURRVAL中存放序列的当前值。
·NEXTVAL应在CURRVAL之前指定,二者应同时有效。

8、使用序列
·将序列值装入内存可提高访问效率。
·序列在下列情况下出现裂缝:
·回滚
·系统异常
·多个表同时使用统一序列
·如果不将序列的值装入内存(NOCACHE),可使用表USER_SEQUENCES查看序列当前的有效值。

9、修改序列
修改序列的增量,最大值,最小值,循环选项,或是否装入内存。
ALTER SEQUENCE dept_deptid_seq
INCREMENT BY 20
MAXVALUE 999999
NOCACHE
NOCYCLE;
修改序列的注意事项
·必须是序列的拥有者或对序列有ALTER权限
·只有将来的序列值会被改变
·改变序列的初始值只能通过删除序列之后重建序列的方法实现。

10、删除序列
·使用DROP SEQUENCE语句删除序列
·删除之后,序列不能再次被引用
DROP SEQUENCE dept_deptid_seq;

11、索引
·一种独立于表的模式对象,可以存储在与表不同的磁盘或表空间中。
·索引被删除或损坏,不会对表产生影响,其影响的只是查询的速度。
·索引一旦建立,Oracle管理系统会对其进行自动维护,而且由Oracle管理系统决定何时使用索引。用户不用在查询语句中指定使用哪个索引。
·在删除一个表时,所有基于该表的索引会自动被删除。
·通过指针加速Oracle服务器的查询速度。
·通过快速定位数据的方法,减少磁盘I/O。

12、创建索引
·自动创建:在定义PRIMARY KEY或UNIQUE约束后系统自动在相应的列上创建唯一性索引。
·手动创建:用户可以在其他列上创建非唯一的索引,以加速查询。
·在一个或多个列上创建索引
CREATE INDEX index ON table (column[,column]…);
·在表EMPLOYEES的列LAST_NAME上创建索引
CREATE INDEX emp_last_name_idx ON employees(last_name);

13、什么时候创建索引
以下情况可以创建索引:
·列中数据值分布范围很广
·列经常在WHERE子句或链接条件中出现
·表经常被访问而且数据量很大,访问的数据大概占数据总量的2%到4%

14、什么时候不要创建索引
下列情况不要创建索引:
·表很小
·列不经常作为连接条件或出现在WHERE子句
·查询的数据大于2%到4%
·表经常更新

15、删除索引
·使用DROP INDEX命令删除索引
·删除索引UPPER_LAST_NAME
·只有索引的拥有者或拥有DROP ANY INDEX权限的用户才可以删除索引

16、同义词
使用同义词访问相同的对象:
·方便访问其他用户的对象
·缩短对象名字的长度

17、创建和删除同义词
·为视图DEPT_SUM_VU创建同义词
CREATE [PUBLIC] SYNONYM synonym FOR object;

·删除同义词
DROP SYNONYM d_sum;



































































































































































































oracle sql以及性能调优相关推荐

  1. SQL Server 性能调优3 之索引(Index)的维护

    SQL Server 性能调优3 之索引(Index)的维护 热度1 评论 16 作者:溪溪水草 SQL Server 性能调优3 之索引(Index)的维护 前言 前一篇的文章介绍了通过建立索引来提 ...

  2. SQL Server性能调优之执行计划深度剖析 第二节 执行计划第一次实践

    SQL Server性能调优之执行计划深度剖析 第二节 执行计划第一次实践 前言:自从上一篇文章发出之后,收到了很朋友的关注.很多朋友要求多多实践,而不是纯粹的理论.确实,从打算出这个系列开始,我就本 ...

  3. SQL Server 性能调优(cpu)

    SQL Server 性能调优(cpu) 研究cpu压力工具 perfom SQL跟踪 性能视图 cpu相关的waitevent Signal wait time SOS_SCHEDULER_YIEL ...

  4. SQL Server 性能调优(方法论)

    SQL Server 性能调优(方法论) 目录 确定思路 wait event的基本troubleshooting 虚拟文件信息(virtual file Statistics) 性能指标 执行计划缓 ...

  5. sql server 性能调优之 资源等待 LCk

    一.  概述 这次介绍实例级别资源等待LCK类型锁的等待时间,关于LCK锁的介绍可参考 "sql server 锁与事务拨云见日".下面还是使用sys.dm_os_wait_sta ...

  6. SQL Server性能调优入门(图文版)

    第一步,在业务高峰期抓取样本数据(2个小时左右).采用的工具是sqlserver自带的profiler,也叫事件探查器,如下图: 进入后,点击最左面的按钮,建立一个新的跟踪: 登录需要用DBO权限,所 ...

  7. 读SQL Server性能调优实战——陈畅亮、吴一晴著

    sqlserver 微软 安装 根据业务特点来考虑 1.分析产品业务数据的增长量 预估某些关键业务数据在一定时间内的增长量,预估数据在未来的增长数据, 2.了解产品业务操作类型.考虑业务是以查询为主还 ...

  8. 每日一题(易错)丨Oracle SQL优化与调优技术

    墨墨导读:本文出自墨天轮"每日一练"专栏,此专栏已连更91天,欢迎关注https://www.modb.pro/topic/26446(复制到浏览器中打开或者点击"阅读原 ...

  9. oracle试图执行计划,Oracle SQL优化与调优之显示执行计划(上)

    通过查询语句显示计划 通过查询语句从这些视图里面读出执行计划并作格式化输出的方法都非常相似,我们这里以 sql_plan 为例给出示例. 通过包 DBMS_XPLAN 显示计划 这个包可以根据我们选择 ...

最新文章

  1. (NO.00002)iOS游戏精灵战争雏形(六)
  2. android studio 断点调试
  3. Opengl-基本概念-对象(很关键啊兄弟这章)
  4. Pycharm运行时找不到文件问题
  5. keyshot详细安装教程
  6. boost::mp11::mp_with_index相关用法的测试程序
  7. android error: undefined reference to 的错误分析
  8. 2013.7.15DAY2
  9. 【转】雷军自曝创业第一年:掏自己的钱创业成功率最高
  10. S. gcc相关软件安装
  11. [VNC] VNC Viewer 远程运行 ffplay 出现错误 GLXBadRenderRequest
  12. 将 Java 作为入门编程语言有错吗?
  13. 使用mysql悲观锁解决并发问题
  14. 申城一叙:SDCC 2017·上海站数据库专场讲师+议题抢鲜版纵览
  15. 帝国php改密码后登录不进去,帝国CMS安装,后台,登陆,密码常见问题汇总
  16. Elasticsearch[2.0] ☞ Java Client API ☞ Percolate API
  17. PC项目——vue 脚手架中实现阿里云人机滑动验证
  18. Libuv的安装及运行使用
  19. 【Spring Boot】 过滤器、监听器、拦截器的使用
  20. 锁定放大器 matlab,锁定放大器的MATLAB建模与仿真

热门文章

  1. 成都Uber优步司机奖励政策(1月17日)
  2. 2016年BYOD四大趋势
  3. 两种红外对管的区别——基于硬件中断(外部中断)测距避障
  4. 为什么 1 字节表示的数值范围是 127 ~ -128
  5. 什么是数据资产?数据资产管理应该如何落地?
  6. BERT生成能力改进:分离对话生成和对话理解
  7. Neural network state estimation for full quantum state tomography笔记
  8. linux之/proc/cpuinfo详解
  9. 服务器被攻击了,更换IP是否有用吗
  10. 中国人民大学计算机考研贴吧,中国人民大学计算机系统结构考研经验-人大信息学院考研辅导班...