以ORACLE數據庫為主
提綱:
第一部分、SQL語言基礎
第一章:Oracle命令類別及sql簡單語法介紹
第二章:oracle的基本函數
第三章:oracle的數據類型
第四章:多表連接技術
第二部分、oracle基本對象及SQL優化
第一章:執行計划
第二章:oracle表
第三章:oracle索引
第四章:oracle分區
第五章:oracle事務和鎖
第六章:oracle hint
第四部分、oracle數據庫管理簡介
第一章:oracle體系結構
第二章:oracle高水位線
第三章:oracle監聽
第四章:flashback
第五章:oracle刪除和卸載
********************************************************
第一章:
Oracle命令類別:
數據操縱語言:DML: select; insert; delete; update; merge.
數據定義語言:DDL: create; alter; drop; truncate; rename; comment.
事務控制語言:TCL: commit; rollback; savepoint.
數據控制語言:DCL: grant; revoke.
sql簡單語法介紹
1.簡單查詢語句執行順序
from, where, group by, having, order by, select
2. 運算符及優先級
算術運算符
*,/,+,-,
邏輯運算符
not, and ,or
SQL>select ename, job, sal ,comm from emp where job='SALESMAN' OR job='PRESIDENT' AND sal> 1500;
等價於
SQL>select ename, job, sal ,comm from emp where job='SALESMAN' OR (job='PRESIDENT' AND sal> 1500);
括號的優先級最高,最好加括號便於理解
比較運算符
單行比較運算 =,>, >=,<,<=, <>
多行比較運算 >any,>all,<any,<all,in,not in
模糊比較 like(配合“%”和“_”)
特殊比較 is null
3.單引號的轉義:連續兩個單引號表示轉義.
SQL> select empno||' is Scott''s empno' from emp where empno=7788;
/*
EMPNO||'ISSCOTT''SEMPNO'
--------------------------------------------------------
7788 is Scott's empno
*/
4.order by
1)位置:order by語句總是在一個select語句的最后面。
2)升序和降序,升序ASC(默認), 降序DESC。有空值的列的排序,缺省(ASC升序)時 null排在最后面
3)混合排序,使用多個列進行排序,多列使用逗號隔開,可以分別在各列后面加升降序。
SQL> select ename,deptno,job from emp order by deptno asc,job desc;
注意
默認不加order by查詢時是按照物理地址rowid排序的,該順序大多數時候和插入的先后順序一致,
但也有很大的可能不一致(如有刪除載插入時),所以需要排序是,只有order by
才能保證結果是正確的。
********************************************************
第二章、oracle的基本函數
(盡量使用數據庫自身提供的函數)
************************
2.1 單行函數與多行函數
單行函數:一行返回一個結果,結果於原記錄數相同。
SQL>select empno,lower(ename) from emp;
注意:where限定from后面的表或視圖,限定的選項只能是表的列或列單行函數或列表達式,
where后不可以直接使用分組函數
SQL> select empno,job from emp where length(job)>5;
分組函數放在having后面
SQL> select deptno,sum(sal) from emp group by deptno having sum(sal)>9000;
多行函數:指多行數據輸入,返回一個值的函數(典型的是聚合函數)
SQL>select sum(sal) from emp;
特殊的單行聚合函數(有叫窗口函數的):
如:
sum() over (partition by order by )
count() over (partition by order by )
min() over (partition by order by )
max() over (partition by order by )
avg() over (partition by order by )
實例:
select t.*,count(t.empno)over() from emp t; --不要count空字段
select t.*,count(t.empno)over(partition by deptno) from emp t;
加order by
select t.*,count(t.empno)over(partition by deptno order by t.empno asc) from emp t;
舉例:查詢所有員工及其所在部門的平均工資,並在部門內按工資由高到底排序
select t.*,avg(t.sal)over(partition by deptno order by t.sal desc) from emp t ;
select t.*,avg(t.sal)over(partition by deptno ) from emp t order by t.sal desc;
select t.*,avg(t.sal)over(partition by deptno ) from emp t order by t.deptno,t.sal desc;
************************
2.2幾種有用的單行函數
2.2.1字符函數
lower('SQL Course')----->sql course 返回小寫
upper('sql course')----->SQL COURSE 返回大寫
initcap('SQL course')-----> Sql Course 返回首字母大寫
concat('good','string')---->good string 拼接 //只能拼接2個字符串
substr('String',1,3)---->Str 從第1位開始截取3位數
instr('t#i#m#r#a#n#','#',3) --->4 從第3位起始找#字符在那個絕對位置
length('String')---->6 長度
lpad('first',10,'$')左填充
rpad(676768,10,'*')右填充
replace('JACK and JUE','J','BL')---->BLACK and BLUE
trim( ' hello ')---->hello
ltrim( ' hello ')
rtrim( ' hello ')
trim('l' from 'lhelloll')---->hello
translate('abcde','cf','12')----->ab1de2g 注意db2寫法:translate('abcdefg','12','cf')
與replace的區別,一個是字符串替換,一個是字符替換。
強大的正則表達式函數
ORACLE中的支持正則表達式的函數主要有下面四個: (db2暫時沒有發現有內置該類函數)
1,REGEXP_LIKE :與LIKE的功能相似
2,REGEXP_INSTR :與INSTR的功能相似
3,REGEXP_SUBSTR :與SUBSTR的功能相似
4,REGEXP_REPLACE :與REPLACE的功能相似
(需要用到的時候自己查找學習)
示例一:
將字符串 go12od ev3e4nin676g 中的所有數字去掉
select replace(translate('go12od ev3e4nin676g','1234567890','1'),'1','') from dual;
select regexp_replace('go12od ev3e4nin676g','[[:digit:]]','') from dual;
如果只去掉連着的數字
select regexp_replace('go12od ev3e4nin676g','[[:digit:]][[:digit:]]+','') from dual;
示例二:
變量截取,將字符串 sdifidso@s_sdfoijdsi12@eefdsfd@sdfds@ 中被@包圍,以s_開頭的字符串
select regexp_substr('sdifidso@s_12@eefdsfd@s1223@','@s_.+?@') from dual;
?此處代表非貪心模式,否則
select regexp_substr('sdifidso@s_12@eefdsfd@s1223@','@s_.+@') from dual;
2.2.2 數值函數
round 四舍五入
mod(100,12) 取余數
ceil向上取整
floor向下取整
trunc截斷取整
2.2.3日期函數
日期轉換函數 to_date等
日期加減函數 add_month等
日期時間差函數 可以精確到 年月日時分秒
注意db2日期函數與oracle區別較大,使用時具體分析
例如
日期加一天 oracle date+1 db2 date + 1d
2.2.4 進制轉換函數
1.十六進制轉十進制
select to_number('1b','xxx') from dual
2.十進制轉十六進制
select to_char(27,'xxx') from dual
2.2.5 空值轉換函數
nvl(ext1,ext2) ex1值為空則返回ex2,否則返回該值本身ex1
nullif(ex1,ex2) 值相等返空,否則返回第一個值
coalesce(ex1,ex2,...,)返回列表中第一個非空表達式
nvl2(ex1,ex2,ex3) 如果ex1不為空,顯示ex2,否則顯示ex3
空值問題:
主要是匹配問題,因為空值不與任何值相等
示例1:簡單匹配
SQL> select count(*) from emp;
COUNT(*)
----------
14
SQL> select count(*) from emp t where t.comm=300;
COUNT(*)
----------
1
SQL> select count(*) from emp t where t.comm<>300;
COUNT(*)
----------
3
或者是查詢 工資和福利不相等的
SQL> select * from emp t1 where t1.sal <> t1.comm;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
7499 ALLEN SALESMAN 7698 20-2月 -81 1600 300 30
7521 WARD SALESMAN 7698 22-2月 -81 1250 500 30
7654 MARTIN SALESMAN 7698 28-9月 -81 1250 1400 30
7844 TURNER SALESMAN 7698 08-9月 -81 1500 0 30
注意 聚集函數會忽略空值
示例2: not in 遇到空值
SQL> update emp t set t.deptno='' where t.deptno=10;
已更新3行。
SQL> select * from emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-12月-80 800 20
7499 ALLEN SALESMAN 7698 20-2月 -81 1600 300 30
7521 WARD SALESMAN 7698 22-2月 -81 1250 500 30
7566 JONES MANAGER 7839 02-4月 -81 2975 20
7654 MARTIN SALESMAN 7698 28-9月 -81 1250 1400 30
7698 BLAKE MANAGER 7839 01-5月 -81 2850 30
7782 CLARK MANAGER 7839 09-6月 -81 2450
7788 SCOTT ANALYST 7566 19-4月 -87 3000 20
7839 KING PRESIDENT 17-11月-81 5000
7844 TURNER SALESMAN 7698 08-9月 -81 1500 0 30
7876 ADAMS CLERK 7788 23-5月 -87 1100 20
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
7900 JAMES CLERK 7698 03-12月-81 950 30
7902 FORD ANALYST 7566 03-12月-81 3000 20
7934 MILLER CLERK 7782 23-1月 -82 1300
已選擇14行。
SQL> select * from dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> select * from dept t1 where t1.deptno not in (select deptno from emp);
未選定行
應該為(前提沒有編號為0的部門):
SQL> select * from dept t1 where t1.deptno not in (select nvl(deptno,0) from emp);
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
40 OPERATIONS BOSTON
或最好改為 not exists
SQL> select * from dept t1 where not exists (select 1 from emp t2 where t1.deptno=t2.deptno);
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
40 OPERATIONS BOSTON
此外,表尾部的null列不占用空間,表設計時盡量將可能空值的列放到最后
2.2.6其他函數
1.CHR()函數和ASCII()函數
chr()函數將ASCII碼轉換為字符: ASCII碼 –》 字符
ascii()函數將字符轉換為ASCII碼:字符 –》 ASCII碼
在oracle中chr()函數和ascii()是一對反函數。
求字符對應的ASCII值
SQL> select ASCII('A') FROM dual;
ASCII('A')
----------
65
SQL> select chr(65) from dual;
C
-
A
2.decode函數與case when函數
decode用法:
SELECT job, sal,
DECODE(job, 'ANALYST', SAL*1.1,
'CLERK', SAL*1.15,
'MANAGER', SAL*1.20,
SAL)
REVISED_SALARY
FROM emp
case when 寫法:
select job, sal,case job
when 'ANALYST' then SAL*1.1
when 'CLERK' then SAL*1.15
when 'MANAGER' then SAL*1.20
else sal end
REVISED_SALARY
from emp
/
或
select job, sal,
case when job='ANALYST' then SAL*1.1
when job='CLERK' then SAL*1.15
when job='MANAGER' then SAL*1.20
else sal end
REVISED_SALARY
from emp
/
不同是case when功能更強大,不過decode寫法比較簡單,
select ename,sal,
case when sal>=3000 then '高級'
when sal>=2000 then '中級'
else '低級' end
級別
from emp
/
第三章、oracle的數據類型
3.1 四種基本的常用數據類型
1、字符型, 2、數值型,3、日期型,4、大對象型
3.1.1 字符型:
char 固定字符,最長2000個
varchar2 可變長字符,最長4000個,最小值是1 (在oracle中與varchar等價)
nchar/nvarchar2 NCHAR/NVARCHAR2類型的列使用國家字符集
nvarchar2(1)能存儲一個字符具體暫用幾個字節根據字符集而定,而上面兩種是字節數
raw和long raw 固定/可變長度的二進制數據長度 最長2G,可存放多媒體圖象聲音等。(老類型,逐步淘汰)
LONG 可變長的字符串數據,最長2G,LONG具有VARCHAR2列的特性,一個表中最多一個LONG列。(老類型,逐步淘汰)。
注意char和varchar2的區別:
1.char是固定長度,varchar2是變長
2.匹配時char也匹配空格
示例:
SQL> create table test(c1 char(10),c2 varchar2(10));
表已創建。
SQL> insert into test(c1,c2) values('a','a');
已創建 1 行。
SQL> select * from test;
C1 C2
---------- ----------
a a
SQL> select * from test where c1=c2;
未選定行
需要改為
SQL> select * from test where trim(c1)=c2;
C1 C2
---------- ----------
a a
或
SQL> select * from test where c1=rpad(c2,10);
C1 C2
---------- ----------
a a
第二種更好些,因為第一種很容易導致c1列上的索引失效
3.varchar2比char節省空間,使用時盡量使用varchar2。
4.行尾的null字段並不耗用任何的存儲空間(對於char,varchar2,number都是的,所以在設計表盡量將可能為空的字段放到末尾)
示例1:
SQL> create table t1(c1 varchar2(20));
SQL> create table t2(c1 char(20));
SQL> select * from user_segments;
未創建段,11g增加的段延遲創建功能。(注意:在用exp導出時,沒有創建段的表不會被導出,可能會出現少表,最好用數據泵expdp導出)
SQL>
begin
for i in 1..10000 loop
insert into t1 values(null);
end loop;
end;
/
SQL>
begin
for i in 1..10000 loop
insert into t2 values(null);
end loop;
end;
/
SQL> select * from user_segments;
消耗的空間相同(主要為塊頭部和塊預留的空閑本分占用)
SQL> update t1 set c1='1';
SQL> update t2 set c1='1';
SQL> select * from user_segments;
能看出char比varchar2消耗更多的空間,同時t2會發生行遷移,較多時會對性能影響較大。
SQL> analyze table t2 compute statistics
SQL> select pct_free,pct_used,avg_row_len,chain_cnt from user_tables where table_name='T2';
PCT_FREE PCT_USED AVG_ROW_LEN CHAIN_CNT
---------- ---------- ----------- ----------
10 29 9152
發生了行遷移
ppt -7
t1不會因為t1可以利用塊中的freespace
SQL> analyze table t1 compute statistics
2 /
Table analyzed
SQL> select pct_free,pct_used,avg_row_len,chain_cnt from user_tables where table_name='T1';
PCT_FREE PCT_USED AVG_ROW_LEN CHAIN_CNT
---------- ---------- ----------- ----------
10 5 0
3.1.2 數值型:
3中固有類型來存儲數值
NUMBER:精度可達38位,邊長格式,長度為0-22字節,這是目前最為常用的數字類型。 范圍 10(-130) 到10(126)之間的任何數
BINARY_FLOAT:單精度浮點數,長度為5個字節,4個用於存儲浮點數,一個用於存長度 -10(38.53) 到 +10(38.53) 精度6位
BINARY_DOUBLE:雙精度浮點數,長度為9字節,8位存浮點數,1位存長度 范圍 -10(308.25) 到 +10(308.25) 精度13位
number精度更大,但BINARY_DOUBLE可存儲更大或更小的值
支持非固定數據類型
numetric(p,s) decimal(p,s) integer或int float double real
底層都只是number類型
3.1.3 日期型:
date 日期的普通形式,表示精度只能到秒級。
timestamp 日期的擴展形式,表示精度可達秒后小數點9位(10億分之1秒)。
timestamp with timezone 帶時區
timestamp with local timezone 時區轉換成本地日期
3.1.4 LOB型:大對象是10g 引入的,在11g中又重新定義,在一個表的字段里存儲大容量數據,所有大對象最大都可能達到4G
CLOB: 用來存儲單字節的字符數據,包含在數據庫內。
NCLOB:用來存儲多字節的字符數據
BLOB:用於存儲二進制數據,包含在數據庫內。
BFILE:存儲在數據庫之外的二進制文件中,這個文件中的數據只能被只讀訪問。
CLOB,NCLOB,BLOB都是內部的LOB類型,沒有LONG只能有一列的限制
保存圖片或電影使用BLOB最好、如果是小說則使用CLOB最好。
雖然LONG RAW也可以使用,但LONG是oracle將要廢棄的類型,因此建議用LOB。
第四章:多表連接技術
交叉連接(笛卡爾積)
非等值連接
等值連接 (內連)
外連接 (內連的擴展,左外,右外,全連接)
自連接
自然連接(內連,隱含連接條件,自動匹配連接字段)
復合連接 (多個結果集進行並、交、差)
范例:
create table a (id int, name char(10));
create table b (id int, loc char(10));
insert into a values (1,'a');
insert into a values (2,'b');
insert into a values (2,'c');
insert into a values (4,'d');
insert into b values (1,'A');
insert into b values (2,'B');
insert into b values (3,'C');
commit;
SQL> select * from a;
ID NAME
---------- ----------
1 a
2 b
2 c
4 d
SQL> select * from b;
ID LOC
---------- ----------
1 A
2 B
3 C
4.2.1 交叉連接(笛卡爾積)
連接條件無效或被省略,兩個表的所有行都發生連接,所有行的組合都會返回(n*m)
SQL99寫法:
SQL> select * from a cross join b;
oracle寫法:
SQL> select * from a,b;
ID NAME ID LOC
---------- ---------- ---------- ----------
1 a 1 A
2 b 1 A
2 c 1 A
4 d 1 A
1 a 2 B
2 b 2 B
2 c 2 B
4 d 2 B
1 a 3 C
2 b 3 C
2 c 3 C
4 d 3 C
已選擇12行。
非等值連接:(連接條件非等值,也屬於內連范疇)
SQL99寫法:
SQL> select empno,ename,sal,grade,losal,hisal
from emp join salgrade
on sal between losal and hisal;
oracle寫法:
SQL> select empno,ename,sal,grade,losal,hisal
from emp,salgrade
where sal between losal and hisal;
EMPNO ENAME SAL GRADE LOSAL HISAL
---------- ---------- ---------- ---------- ---------- ----------
7369 SMITH 800 1 700 1200
7900 JAMES 950 1 700 1200
7876 ADAMS 1100 1 700 1200
7521 WARD 1250 2 1201 1400
7654 MARTIN 1250 2 1201 1400
7934 MILLER 1300 2 1201 1400
7844 TURNER 1500 3 1401 2000
7499 ALLEN 1600 3 1401 2000
7782 CLARK 2450 4 2001 3000
7698 BLAKE 2850 4 2001 3000
7566 JONES 2975 4 2001 3000
7788 SCOTT 3000 4 2001 3000
7902 FORD 3000 4 2001 3000
7839 KING 5000 5 3001 9999
4.2.2 等值連接,典型的內連接
SQL99寫法:
SQL> select * from a inner join b on a.id=b.id;
oracle寫法:
SQL> select * from a,b where a.id=b.id;
ID NAME ID LOC
---------- ---------- ---------- ----------
1 a 1 A
2 b 2 B
2 c 2 B
4.2.3 外連接包括左外連接,右外連接,全外連接
1)左外連接
SQL99語法:
SQL> select * from a left join b on a.id=b.id;
oracle語法:
SQL> select * from a,b where a.id=b.id(+);
結果:
ID NAME ID LOC
---------- ---------- ---------- ----------
1 a 1 A
2 c 2 B
2 b 2 B
4 d
2)右外連接
SQL99語法:
SQL>select * from a right join b on a.id=b.id;
oracle語法:
SQL> select * from a,b where a.id(+)=b.id;
結果
ID NAME ID LOC
---------- ---------- ---------- ----------
1 a 1 A
2 b 2 B
2 c 2 B
3 C
3)全外連接
SQL99語法:
SQL> select * from a full join b on a.id=b.id;
ID NAME ID LOC
---------- ---------- ---------- ----------
1 a 1 A
2 b 2 B
2 c 2 B
4 d
3 C
oracle語法:
SQL> select * from a,b where a.id=b.id(+)
union
select * from a,b where a.id(+)=b.id;
ID NAME ID LOC
---------- ---------- ---------- ----------
1 a 1 A
2 b 2 B
2 c 2 B
4 d
3 C
4.2.4 自連接
sql99語法:
SQL> select * from a cross join a;
oracle語法:
SQL> select * from a a1,a a2;
ID NAME ID NAME
---------- ---------- ---------- ----------
1 a 1 a
1 a 2 b
1 a 2 c
1 a 4 d
2 b 1 a
2 b 2 b
2 b 2 c
2 b 4 d
2 c 1 a
2 c 2 b
2 c 2 c
2 c 4 d
4 d 1 a
4 d 2 b
4 d 2 c
4 d 4 d
已選擇16行。
4.2.5 自然連接(屬於內連中等值連接)
在oralce中使用natural join,也就是自然連接。
先看自然連接:
SQL> select * from a natural join b;
ID NAME LOC
---------- ---------- ----------
1 a A
2 b B
2 c B
-----將兩個表分別再加一個列ABC后,則有兩個公共列(ID列和ABC列),添加數據后,再嘗試自然連接如何匹配。
SQL> select * from a;
ID NAME ABC
---------- ---------- ----------
1 a s
2 b t
2 c u
4 d v
SQL> select * from b;
ID LOC ABC
---------- ---------- ----------
1 A w
2 B t
3 C r
SQL> select * from a natural join b;
ID ABC NAME LOC
---------- ---------- ---------- ----------
2 t b B
在自然連接中可以使用using關鍵字:
當使用natraul join關鍵字時,如果兩張表中有多個字段,它們具有相同的名稱和數據類型,那么這些字段都將被oracle自作主張的將他們連接起來。但如果名稱相同,類型不同,或者當你需要在多個字段同時滿足連接條件的情況下,想人為指定某個(些)字段做連接,那么可以使用using 關鍵字。
在oracle連接(join)中使用using關鍵字
SQL> select id,a.abc,name,loc from a join b using(id);
ID ABC NAME LOC
---------- ---------- ---------- ----------
1 s a A
2 t b B
2 u c B
using里未必只能有一列
SQL> select id,abc,name,loc from a join b using(id,abc);
ID ABC NAME LOC
---------- ---------- ---------- ----------
2 t b B
在實際工作中看,內連接,左外連接用的較多
左連接與內連接 示例:(查詢每個部門的平均工資)
方法一:內連接
select t1.deptno, t1.dname, nvl(avg(t2.sal), 0)
from dept t1, emp t2
where t1.deptno = t2.deptno
group by t1.deptno, t1.dname;
DEPTNO DNAME NVL(AVG(T2.SAL),0)
------ -------------- ------------------
10 ACCOUNTING 2916.66666666667
20 RESEARCH 2175
30 SALES 1566.66666666667
(沒有40號部門的統計數據)
方法二:左連接
select t1.deptno, t1.dname, nvl(avg(t2.sal),0)
from dept t1
left join emp t2
on t1.deptno = t2.deptno
group by t1.deptno, t1.dname;
DEPTNO DNAME NVL(AVG(T2.SAL),0)
------ -------------- ------------------
10 ACCOUNTING 2916.66666666667
40 OPERATIONS 0
20 RESEARCH 2175
30 SALES 1566.66666666667
4.3.復合查詢(使用集合運算符)
Union,對兩個結果集進行並集操作,不包括重復行,同時進行默認規則的排序;
Union All,對兩個結果集進行並集操作,包括所有重復行,不進行排序;
Intersect,對兩個結果集進行交集操作,不包括重復行,同時進行默認規則的排序;
Minus,對兩個結果集進行差操作,不包括重復行,同時進行默認規則的排序。
4.3.子查詢關聯更新問題
SQL> create table t1(id int,name varchar2(10));
Table created
SQL> create table t2(id int,name varchar2(10));
Table created
SQL> insert into t1(id,name) values (1,'a1');
1 row inserted
SQL> insert into t1(id,name) values (2,'b1');
1 row inserted
SQL> insert into t1(id,name) values (3,'c1');
1 row inserted
SQL> insert into t2(id,name) values (1,'a2');
1 row inserted
SQL> insert into t2(id,name) values (2,'b2');
1 row inserted
SQL> commit;
Commit complete
SQL> select * from t1;
ID NAME
--------------------------------------- ----------
1 a1
2 b1
3 c1
SQL> select * from t2;
ID NAME
--------------------------------------- ----------
1 a2
2 b2
拿t2中的數據去更新t1
SQL> update t1 set t1.name=(select name from t2 where t1.id=t2.id);
3 rows updated
SQL> select * from t1;
ID NAME
--------------------------------------- ----------
1 a2
2 b2
3
發現id=3的數據被更新成空
SQL> rollback;
Rollback complete
SQL> update t1 set t1.name=(select name from t2 where t1.id=t2.id)
where exists(select 1 from t2 where t1.id=t2.id);
2 rows updated
SQL> select * from t1;
ID NAME
--------------------------------------- ----------
1 a2
2 b2
3 c1
根據現實情況決定是否要加 where條件限制
4.4多表連接中的三種表連接
多表連接時,oracle一次只能連接兩個表,優化器從一個表開始,將他與下一個表連接,再將中間結果與接下來的表相連接,直到結束返回結果。
嵌套循環(nested loop join)
排序合並(SORT MERGE JOIN)
哈希連接(HASH JOIN)
4.4.1.嵌套循環(nested loop join)
原理:選定一張表做為驅動表也稱為外部表,Oracle會遍歷驅動表中的每一行,根據連接條件去匹配第二張表(內部表)中的行。
注意點:
1.適用於被連接的數據子集比較小的情況
2.在內部表上最好有基於連接條件的索引且區分度較好。
3.外部表與內部表的選擇很重要,最好是小表最為外部表以減少IO
4.使用oracle提示 USE_NL(TABLE1,table2) 強制使用該鏈接方式
示例:
select /*+use_nl(t1,t2)*/* from dept t1, emp t2 where t1.deptno = t2.deptno
4.4.2排序合並(SORT MERGE JOIN)
原理:(1)先對每個數據子集進行全表掃描並(2)對排序結果進行合並(從一個排序表中取出數據到另一個排序表中進行匹配)
注意點:
1.由於排序資源消耗較大,所以這種連接方式一般來所沒有有hosh join經濟,提別是大表連接時。
2.檔數據源已排序的情況下可能會選擇該方式
3.不等值連接(<>,<,>)和not like及like的情況,有可能。
4.使用提示USE_MERGE(TABLE1,table2)強制使用該方式
示例:
select /*+use_merge(t1,t2)*/* from dept t1, emp t2 where t1.deptno = t2.deptno
4.4.2.哈希連接(HASH JOIN)
這是比較常用的連接方式
原理:優化器首先掃描較小的表,利用連接鍵在內存中通過hash函數建立hash表(bitmap位圖方式),然后掃描大表,每讀到一條記錄就通過該hash函數計算hash值來探測hash表,找出與hash表匹配的行。
注意點:
(1)如果是小表可以全部放到內存,則連接成本接近兩個表全表掃描的成本之和。
(2)如果表比較大,優化器就會將其分割為不同的分區,把不能放入內存的部分寫入磁盤的臨時段。臨時段的內容需要再讀入內存做hash連接。此時的代價接近
全表掃描小表+分區數*全表掃描大表
(3)適用於兩大大表之間的連接或大表與小表之間的連接
(4)hash連接不使用索引
(5)使用提示USE_HASH(TABLE1,table2)強制使用該方式
示例:
select /*+use_hash(t1,t2)*/* from dept t1, emp t2 where t1.deptno = t2.deptno
第二部分、oracle基本對象及SQL優化
第一章:執行計划
1.查看執行計划的幾個要點
select * from dept t1, emp t2,emp_bak t3 where t1.deptno = t2.deptno and t2.empno=t3.empno;
第二章:oracle表
1.堆表
最常見的表
2.臨時表
臨時表存放在當前登錄的臨時表空間下,它被每個session單獨使用,即:不同session看到的臨時表中的數據不一樣。
兩種模式:
1)基於事務的臨時段:在事務提交時,就會自動刪除記錄,on commit delete rows。
create global temporary table tmp_test1(id int)
on commit delete rows;
2)基於會話的臨時段:當用戶退出session 時,才會自動刪除記錄, on commit preserve rows。
create global temporary table tmp_test2(id int)
on commit preserve rows;
好處:
1)session之間數據隔離,有利於並行處理互不影響
2)只記錄少量undo的redo日志,不計直接數據變動的redo日志
3.索引組織表
ppt
如果表經常以主鍵查詢,可以考慮建立索引組織表,加快表的訪問速度.
在索引組織表中,數據是有序排列的
ppt-36
示例:
create table test_n(id int, name varchar2(50),
constraint pk_test_n primary key (id))
;
create table test_iot(id int, name varchar2(50),
constraint pk_test_iot primary key (id))
organization index ;
insert into test_n select empno,ename from emp;
insert into test_iot select empno,ename from emp;
select * from user_segments; --索引組織表沒有創建表段
查看執行計划
select * from iot_test1 t where t.id='7788';
select * from iot_test2 t where t.id='7788';
4.聚簇表
5.外部表
第三章:oracle索引
建測試表:
SQL> create table test_ind as select * from all_objects;
create unique index PK_TEST_IND on TEST_IND (OBJECT_ID)
按唯一性分有:唯一索引和非唯一索引 (唯一索引+not null=主鍵)
按機制分有:
1.b-tree索引
ppt-35
Index Scans:
1)Full Index Scan
掃描整個索引,有排序操作
示例:
select * from EMP T WHERE T.SAL>2000 ORDER BY T.EMPNO
2)Fast Full Index Scan
所需要的列都在索引里,不需要訪問表
示例:
select object_id from test_ind
3)Index Range Scan
使用index rang scan的3種情況:
(a) 在唯一索引列上使用了range操作符(> < <> >= <= between)
(b) 在唯一組合索引上,對組合索引使用部分列進行查詢(含引導列),導致查詢出多行
(c) 對非唯一索引列上進行的任何查詢。不含‘布爾或’
示例一:
select * from test_ind t where t.object_id<100
示例二:
create index IND_TEST_IND_N on TEST_IND (OBJECT_TYPE)
select object_id from test_ind t where t.object_type='SEQUENCE';
4)Index Unique Scan
精確訪問效率最高
示例一:
select * from test_ind t where t.object_id=100
5)Index Skip Scan
適用於 條件沒有前綴索引,但前綴索引區分度較小,但條件中的字段區分度較大
示例:
create index IND_TEST_SKIP on TEST_IND (OWNER, OBJECT_ID)
select * from test_ind t where t.object_id='100'
?
培訓的時候沒有演示成功,主要是由於統計信息不准確造成的,因為該索引掃描需要更詳細的統計信息。
由此也可見統計信息對oracle執行計划的重要性。
對表做一下信息統計:
begin
dbms_stats.gather_table_stats(ownname => 'scott',
tabname => 'TEST_IND',
cascade => TRUE,
degree => 4,
estimate_percent => 100);
end;
再看執行計划:
SQL> explain plan for select * from test_ind t where t.object_id='100';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 234563464
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 104 | 33 (0
| 1 | TABLE ACCESS BY INDEX ROWID| TEST_IND | 1 | 104 | 33 (0
|* 2 | INDEX SKIP SCAN | IND_TEST_SKIP | 1 | | 32 (0
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T"."OBJECT_ID"=100)
filter("T"."OBJECT_ID"=100)
否則:
create index IND_TEST_SKIP2 on TEST_IND (OBJECT_ID,OWNER)
select * from test_ind t where t.owner='SCOTT'
發現全表掃描,沒有使用Index Skip Scan,因為OBJECT_ID分區度大,OWNER區分度小。
2.bit-map位圖索引
ppt-45
適用於 重復數較少的情況,對於count運算效率最高
不適用於並發環境
示例:
create bitmap index IND_TEST_BITMAP on TEST_IND (OBJECT_TYPE)
select object_id from test_ind t where t.object_type='SEQUENCE';
3.基於函數的索引
字段加函數后索引一般會失去作用,由原理可知
示例:
create index IND_TEST_IND_N on TEST_IND (OBJECT_TYPE)
select object_id from test_ind t where lower(t.object_type)='sequence';
SQL> create index IND_TEST_IND_N2 on TEST_IND (lower(object_type));
select object_id from test_ind t where lower(t.object_type)='sequence';
總結:
1.索引雖然會或多或少降低插入的數度,但卻能大大提高查詢的效率,一般來說建索引是值得的,特別對於OLTP系統,非常關鍵。
2.如果可能盡可能避免訪問原表
3.根據不同的數據分布和使用條件來創建索引
第四章:oracle分區
分區表類型:
單層分區
range
list
hash
多層分區
range -- rang
range -- list
range -- hash
list -- range 等所有組合
hash
舉例:range
CREATE TABLE time_range_sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id)
(PARTITION SALES_1998 VALUES LESS THAN (TO_DATE('01-JAN-1999','DD-MON-YYYY')),
PARTITION SALES_1999 VALUES LESS THAN (TO_DATE('01-JAN-2000','DD-MON-YYYY')),
PARTITION SALES_2000 VALUES LESS THAN (TO_DATE('01-JAN-2001','DD-MON-YYYY')),
PARTITION SALES_2001 VALUES LESS THAN (MAXVALUE)
);
ppt -46
舉例:list
CREATE TABLE list_sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY LIST (channel_id)
(PARTITION even_channels VALUES (2,4),
PARTITION odd_channels VALUES (3,9)
);
ppt-47
舉例:hash
CREATE TABLE hash_sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY HASH (prod_id)
PARTITIONS 2;
優點:1.物理上每個分區的數據存在一起,查詢時能直接跳過不必要的分區
2.便於清楚數據,可以直接清空分區 alter table table_name truncate partition p5;
缺點:插入時消耗cpu
第五章:oracle事務和鎖
一,什么是事務
必須具備以下四個屬性,簡稱ACID 屬性:
原子性(Atomicity): 事務是一個完整的操作。事務的各步操作是不可分的(如原子不可分);各步操作要么都執行了,要么都不執行。
一致性(Consistency):1)一個事務結束之后,所有會話發起的查詢所看到的該事務的結果都是一致的(commit后的查詢有同樣的結果)。
2)一個查詢的結果必須與數據庫在查詢開始時的狀態保持一致(讀不等寫,寫不等讀)。
隔離性(Isolation): 某個會話正在進行的事務所引起的變更對於其他會話來說必須不可見。
持久性(Durability): 事務一旦提交完成后,數據庫就不可以丟失這個事務的結果,數據庫通過日志能夠保持事務的持久性。
10.2 事務的開始和結束
10.2.1 事務采用隱性的方式,起始於session的第一條DML語句,
10.2.2 事務結束於:
1)COMMIT(提交)或ROLLBACK(回滾)
2)DDL語句被執行(提交)
3)DCL語句被執行(提交)
4)用戶退出SQLPLUS(正常退出是提交,非正常退出是回滾)
5)服務器故障或系統崩潰(回滾)
6)shutdowm immediate(回滾)
二.鎖類型:
oracle讀不會鎖表
1.DML鎖
(1)TX
(2)TM
2.DDL鎖
(1)排他DDL鎖
(2)共享DDL鎖
(3)可中斷解析鎖
第六章:oracle hint
Hint 是Oracle 提供的一種SQL語法,它允許用戶在SQL語句中插入相關的語法,從而影響SQL的執行方式。
因為Hint的特殊作用,所以對於開發人員不應該在代碼中使用它,Hint 更像是Oracle提供給DBA用來分析問題的工具 。
在SQL代碼中使用Hint,可能導致非常嚴重的后果,因為數據庫的數據是變化的,在某一時刻使用這個執行計划是最優的,
在另一個時刻,卻可能很差,這也是CBO 取代RBO的原因之一,規則是死的,而數據是時刻變化的,為了獲得最正確的執行計划,
只有知道表中數據的實際情況,通過計算各種執行計划的成本,則其最優,才是最科學的,這也是CBO的工作機制。
在SQL代碼中加入Hint,特別是性能相關的Hint是很危險的做法。
在使用Hint時需要注意的一點是,並非任何時刻Hint都起作用。
導致HINT 失效的原因有如下2點:
(1) 如果CBO 認為使用Hint 會導致錯誤的結果時,Hint將被忽略。如索引中的記錄因為空值而和表的記錄不一致時,結果就是錯誤的,會忽略hint。
(2) 如果表中指定了別名,那么Hint中也必須使用別名,否則Hint也會忽略。
如:
Select /*+full(a)*/ * from t a; -- 使用hint
Select /*+full(t) */ * from t a; --不使用hint
第七章:oracle表空間
SQL> select * from dba_tablespaces;
ppt-44
1.system表空間
主要存放數據字典信息(各種視圖),存儲過程,觸發器,包等,是很重要的表空間,損壞后數據庫即不可用
2.SYSAUX
是system表空間的輔助表空間,存儲system表空間之外的元數據,如快照信息,awr報告,oem等使用該表空間存儲信息
3.undo表空間
undo的作用
1)使用undo tablespace 存放從datafiles 讀出的數據塊的前鏡像,提供以下四種情況所需要的信息
1)回滾事務:rollback
2)讀一致性:正在做DML操作的數據塊,事務結束前,其他用戶讀undo里面的數據前鏡像
3)實例的恢復:instance recover(undo -->rollback)
4)閃回技術 :flashback query、flashback table等
2)可以建立多個undo表空間,但一個時刻只有一個處於active
SQL> show parameter undo
3)undo 數據的4種狀態
1)active: 表示transaction還沒有commit,不可覆蓋,
2)unexpired:已經commit,但是還在undo_retention內,不可以覆蓋(非強制),加GUARANTEE屬性后強制undo_retention內不覆蓋。
3)expired: 已經commit,且時間超過了undo_retention,隨時可以覆蓋。
4)free: 分配了但未使用過。
undo retention參數和undo autoextend on特性
undo retention參數規定了unexpired commit數據的保留期,它是保證一致性讀,和大多數閃回技術成功的關鍵,
將undo表空間設為autoextend on, 這是DBCA創建數據庫時的缺省設置, 這一個特性將在undo空間不足時優先擴展新的空間,其次才是覆蓋unexpired commit。
如果undo retention=0,則Oracle會啟用undo自動調優,它使用900秒作為undo retention的參考值。然后根據收集到的數據庫中最長查詢及撤銷生成率自動調整undo retention。
4.用戶表空間
存儲用戶數據
5.臨時表空間
存儲不能放入內存的排序數據,臨時表數據,不計日志
第四部分、oracle數據庫管理簡介
第一章:oracle體系結構
見ppt
第二章:oracle高水位線
高水位線(high-water mark,HWM)
在數據庫中,如果把表想象成從左到右依次排開的一系列塊,高水位線就是曾經包含了數據的最右邊的塊。原則上HWM只會增大, 即使將表中的數據全部刪除,HWM也不會降低。
HWM不是好事,使用全表掃描時通常要讀出HWM以下的所有數據塊(盡管該表中可能僅有少量數據),這將白白耗費大量IO資源。
2)兩個解決辦法可降低HWM:
2.1)移動表,move方法, 將表從一個表空間移動到另一個表空間(也可以在本表空間內move)。
語法:alter table t1 move [tablespace users];
優點:可以清除數據塊中的碎片,降低高水位線。
缺點:move需要額外(一倍)的空間。
move過程中會鎖表,其他用戶不能在該表上做DML或DDL操作。
move之后,相關索引都不可用了,表上的索引需要重建。
查看:
select * from user_extents;
delete 不降低高水位線,truncate可以
2.2)收縮表,shrink 也叫段重組,表收縮的底層實現的是通過匹配的INSERT和DELETE操作。
它分兩個不同的階段:壓縮階段和DDL命令階段。(PPT-II-491)
語法:alter table TEST_IND shrink space;
?
沒有演示成功問題是因為我在前面建了一個基於函數的索引,如果選擇第一種move方法的話就不會有問題。
刪除索引后再次執行:
SQL> alter table TEST_IND shrink space;
Table altered
shrink有以下幾點限制
■ IOT mapping tables
■ Tables with rowid based materialized views
■ Tables with function-based indexes
■ SECUREFILE LOBs
■ Compressed tables
優點:前后索引可用
不需要額外的空間
可以先執行壓縮再在高峰期過后執行DDL(會有短暫的鎖等待),可用性高
缺點:產生較多的undo和redo日志
(delete 不會降低高水位線truncate可以)
第三章:oracle監聽
起連接作用,連接成功后即不再負責
ppt-31 32
session與connection的區別
ppt-12
連接池作用
動態監聽與靜態監聽
1)動態監聽:listener 采用的是默認端口(1521),當實例啟動時,由pmon 每分鍾自動將service name,本機的1521端口號注冊到listener
2)靜態監聽:當listener 一般使用的是非標准端口(如1522),在listener.ora的文件里手工注冊(添加GLOBAL_DBNAME 和instance name)
15.3.1 監聽器的動態注冊和靜態注冊
靜態注冊:
1)靜態注冊不需要數據庫打開,通過讀取listener.ora的靜態注冊描述完成監聽器的注冊,因為不需要數據庫open,所以如果服務器端一旦啟動了靜態監聽,便可以通過sqlplu以sys用戶連接到服務器,實現遠程啟動/關閉數據庫的任務。
2)靜態注冊可以使用用戶指定的端口號(非1521),相對隱蔽,安全。
3)靜態注冊在一些特殊場合,如使用數據庫復制技術時是很有用處的。
動態注冊:
1)需要數據庫打開才能注冊成功,所以動態注冊無法使用sysdba身份遠程啟動數據庫。一般都是通過遠程TELNET先以root登錄服務器,這時你已經在服務器本地了,再轉入oracle以sysdba身份打開數據庫。之后監聽器才可以進行動態注冊。
2)使用標准1521端口,自動注冊。
3)可以不使用listener.ora,因為動態注冊由PMON后台進程自動注冊信息,PMON每60秒查看listener進程是否啟動,啟動了就注冊相關服務器信息。
監聽配置
靜態監聽:
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = orcl)
(ORACLE_HOME = d:\app\Administrator\product\11.2.0\dbhome_1)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)
動態監聽:
不用配置 istener.ora 文件
第四章:flashback
1.flashback包括:
flashback query --閃回查詢並不實際修改表的數據。
flashback table --閃回表,恢復表中的數據。
flashback database --閃回數據,可恢復db的數據 (備份恢復內容 暫不講)
.閃回查詢
select * from test as of timestamp sysdate - interval '5' minute;
.閃回表(需要alter table enable row movement)
flashback table tablename to timestamp systimestamp - interval '5' minute;
flashback table tablename to before drop;
該技術依賴於undo表空間
第五章:oracle刪除和卸載
刪除數據庫:
To drop a database with SQL*Plus:
1.SQL> STARTUP RESTRICT FORCE MOUNT
2.SQL> DROP DATABASE;
數據文件和控制文件都會被刪除
3.用操作系統刪除備份和歸檔日志(如果有的話)
卸載數據庫軟件:
Windows下ORACLE 完全卸載:
使用OUI可以卸載數據庫,但卸載后注冊表和文件系統內仍會有部分殘留。這些殘留不僅占用
磁盤空間,而且影響ORACLE的重新安裝及系統性能。
在WINDOWS下卸載ORACLE 10g的步驟:
方法一:
1, 關閉所有oracle的服務和程序
2, 選擇開始| 程序|oracle Installation Products命令,運行Universal Installer,彈出歡迎對話框
3, 單擊卸載產品 按鈕,彈出Inventory對話框
4, 選中Inventroy對話框中的所有節點,點擊刪除,確認即可
5, 選擇 開始|運行 輸入regedit並按ENTER鍵,
選擇 HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE,刪除此象,
然后選擇HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services,滾動此列表,刪除與oracle有關的所 有選項。
6, 從桌面上、STARTUP和程序菜單中刪除所有ORACLE的組和圖標。
7, 重啟系統。
8, 刪除包括文件在內的安裝目錄。至此ORACLE的全部卸載完成。