??xml version="1.0" encoding="utf-8" standalone="yes"?> 一?span class="hilite2">decode ?span class="hilite1">Oracle/PLSQL
? decode h?
IF-THEN-ELSE 一L功能?/span> decode
函数语法如下Q?/span> decode(
expression , search , result [, search , result]... [, default] ) expression 要比较的表达? search 要与expression
比较的字Dc?/em>. result 如果expression
?em>search 一L话,q回该结果? default 此参数可选,如果没有?em>expression
匚w上的search .
p回此l果Q如果此参数没有讄Q当没有与expression匚w上的searchӞq回null?/span> search ?
result可成对出现多ơ,代表各种要匹配的情况?nbsp; 应用?/span> 例如Q?/span> You could use the decode function in an SQL statement as follows: select
supplier_name,decode(supplier_id,1000,'IBM',10001,'Microsoft','1002','Hewlett
Packard','Gateway') result from suppliers; 上面的sql语句相当于下面的IF-THEN-ELSE : IF supplier_id = 10000 THEN ELSIF supplier_id = 10001 THEN ELSIF supplier_id = 10002 THEN ELSE END IF;
问题1:
现在一个阅读者想问,怎么使用decode函数来比较两个日期呢Q(例如Qdate1 ?
date2Q? 如果date1 > date2, decode
函数q回date2. 否则decode函数q回 date1. 回答:
要实Cq要求,可?span class="hilite2">decode函数如下Q?/span> decode((date1
- date2) - abs(date1 - date2), 0, date2, date1) 如果date1大于date2Q下面表达是会等?Q?/span> (date1 - date2) - abs(date1 - date2) 帮助性提C?/strong>: 可用decode函数l定SIGN 函数 像下面这? 上面比较日期的语句可修改如下: DECODE(SIGN(date1-date2), 1, date2, date1) SIGN/DECODE
联合对于有关销售红利等数字斚w的比较是非常有用的?/span> DECODE(SIGN(actual-target),
-1, 'NO Bonus for you', 0,'Just made it', 1, 'Congrats, you are a
winner')
问题2:
我想知道是否可以?span class="hilite2">decode函数来确定数字范_例如 1-10 =
'category 1', 11-20 = 'category 2', 比一个一个比较应该会好一点吧. 回答:
不幸的告诉你Q不可以?span class="hilite2">decode函数来确定数字的范围.
可是你可以试着创徏一个表辑ּQ这个表辑ּ可以得一个数字指定的范围, 下一个数字对应下一个指定的范围, 以此cL. 例如Q?/strong> select
supplier_id,decode(trunc((supplier_id-1)/10),0,'category
1',1,'category 2',2,'category 3','unknown') result from suppliers; q个例子Zq个公式Q?/span>trunc
((supplier_id - 1) / 10 如果supplier_id??0之间Q表辑ּ计算?0. 如果supplier_id?1?0之间Q表辑ּ计算?1.
如果supplier_id?1?0之间Q表辑ּ计算?3. {等Q?
问题3: 我想写一?span class="hilite2">decode函数Q要求如? 如果 yrs_of_service < 1 q回 0.04 q种情况我该怎么做呢? 回答: You will
need to create a formula that will evaluate to a single number for each
one of your ranges. For example: select
emp_name,decode(trunc((yrs_of_service+3)/4),0,0.04,1,0.04,0.06)
as perc_value from employees;
问题4: decode函数的参C数有限制吗?我得C个错?"ORA-00939: too many
arguments for function". 回答: 是的Q?span class="hilite2">decode函数的最大参CCؓ255?包括expression, search,
and result arguments.<!-- InstanceEndEditable --> ------------------------------------------------------------------------------------------------------------- 二、sign ?span class="hilite1">Oracle/PLSQL
? sign 函数q回一个数字的正负标志. 语法如下Q?/span>sign( number ) number
要测试标志的数字. If number < 0, then sign
returns -1. 应用? 例如: would return 1 ---------------------------------------------------------------------------------------------------- 三、trunc(number) ?span class="hilite1">Oracle/PLSQL? trunc
function returns a number truncated to a certain number of decimal
places. trunc function 语法如下: trunc( number, [ decimal_places ] ) number 要截取的数字. decimal_places 要保留的数?
q个参数必须是个整数. 如果此参数缺省,默认保留0位小?/span> 应用? 例如For example: 如果decimal_places 大于number
本n的小C敎ͼq回原数字不会加0. 如:trunc(125.81,3)
would return 125.81; 如果decimal_places
敎ͼ那么指定的位数
1. SELECT子句中避免?“*”
当你惛_SELECT子句中列出所有的COLUMN?使用动态SQL列引?‘*’
是一个方便的Ҏ.不幸的是,q是一个非怽效的Ҏ. 实际?ORACLE在解析的q程? 会将“*” 依次转换成所有的列名,
q个工作是通过查询数据字典完成? q意味着耗费更多的时?
2.使用DECODE函数来减处理时?/strong>
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的? 例如:
3.删除重复记录
最高效的删除重复记录方?( 因ؓ使用了ROWID)
4. 用TRUNCATE替代DELETE
当删除表中的记录Ӟ在通常情况下,回滚D?rollback segments )
用来存放可以被恢复的信息Q如果你没有COMMIT事务QORACLE会将数据恢复到删除之前的状?准确地说是恢复到执行删除命o之前的状?Q而当q?
用TRUNCATE? 回滚D不再存放Q何可被恢复的信息.当命令运行后,数据不能被恢?因此很少的资源被调用,执行旉也会很短.
5.计算记录条数
和一般的观点相反, count(*) 比count(1)E快 Q当然如果可以通过索引索,对烦引列的计C旧是最快的. 例如 COUNT(EMPNO)
6.用Where子句替换HAVING子句
避免使用HAVING子句QHAVING 只会在检索出所有记录之后才对结果集q行qoQ这个处理需要排序、总计{操作,如果能通过WHERE子句限制记录的数目,那就能减这斚w的开销, 例如:
7. 用EXISTS替代IN
在许多基于基表的查询?Z满一个条?往往需要对另一个表q行联接.在这U情况下, 使用EXISTS(或NOT EXISTS)通常提高查询的效率.
8.用NOT EXISTS替代NOT IN
在子查询中,NOT IN子句执行一个内部的排序和合q? 无论在哪U情况下QNOT IN都是最低效?
(因ؓ它对子查询中的表执行了一个全表遍?. Z避免使用NOT INQ我们可以把它改写成外连?Outer Joins)或NOT
EXISTS. 例如:
SELECT …FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=’A’);
9.用EXISTS替换DISTINCT
当提交一个包含一对多表信?比如部门表和雇员?的查询时,避免在SELECT子句中用DISTINCT. 一般可以考虑用EXIST替换
例如:
10. 用烦引提高效?/strong>
索引是表的一个概念部分,用来提高索数据的效率Q实际上ORACLE使用了一个复杂的自^衡B-treel构Q通常通过索引查询数据比全表扫描要快,?
ORACLE扑և执行查询和Update语句的最佌\径时Q?ORACLE优化器将使用索引Q?
同样在联l多个表时用烦引也可以提高效率Q另一个用烦引的好处是,它提供了主键(primary key)的唯一性验证,除了那些LONG或LONG
RAW数据cd, 你可以烦引几乎所有的? 通常, 在大型表中用烦引特别有? 当然,你也会发?
在扫描小表时,使用索引同样能提高效率,虽然使用索引能得到查询效率的提高,但是我们也必L意到它的代h.
索引需要空间来存储Q也需要定期维护,每当有记录在表中增减或烦引列被修ҎQ烦引本w也会被修改Q这意味着每条记录的INSERT , DELETE ,
UPDATEؓ此多付出4 , 5 ơ的盘I/OQ?因ؓ索引需要额外的存储I间和处理,那些不必要的索引反而会使查询反应时间变?
注:定期的重构烦引是有必要的.
11. 避免在烦引列上用计?/strong>
WHERE子句中,如果索引列是函数的一部分Q优化器不使用索引而用全表扫? 举例Q?
12. ?gt;=替代>
当你惛_SELECT子句中列出所有的COLUMN?使用动态SQL列引?‘*’
是一个方便的Ҏ.不幸的是,q是一个非怽效的Ҏ. 实际?ORACLE在解析的q程? 会将“*” 依次转换成所有的列名,
q个工作是通过查询数据字典完成? q意味着耗费更多的时?
2.使用DECODE函数来减处理时?/strong>
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的? 例如:
3.删除重复记录
最高效的删除重复记录方?( 因ؓ使用了ROWID)
4. 用TRUNCATE替代DELETE
当删除表中的记录Ӟ在通常情况下,回滚D?rollback segments )
用来存放可以被恢复的信息Q如果你没有COMMIT事务QORACLE会将数据恢复到删除之前的状?准确地说是恢复到执行删除命o之前的状?Q而当q?
用TRUNCATE? 回滚D不再存放Q何可被恢复的信息.当命令运行后,数据不能被恢?因此很少的资源被调用,执行旉也会很短.
5.计算记录条数
和一般的观点相反, count(*) 比count(1)E快 Q当然如果可以通过索引索,对烦引列的计C旧是最快的. 例如 COUNT(EMPNO)
6.用Where子句替换HAVING子句
避免使用HAVING子句QHAVING 只会在检索出所有记录之后才对结果集q行qoQ这个处理需要排序、总计{操作,如果能通过WHERE子句限制记录的数目,那就能减这斚w的开销, 例如:
7. 用EXISTS替代IN
在许多基于基表的查询?Z满一个条?往往需要对另一个表q行联接.在这U情况下, 使用EXISTS(或NOT EXISTS)通常提高查询的效率.
8.用NOT EXISTS替代NOT IN
在子查询中,NOT IN子句执行一个内部的排序和合q? 无论在哪U情况下QNOT IN都是最低效?
(因ؓ它对子查询中的表执行了一个全表遍?. Z避免使用NOT INQ我们可以把它改写成外连?Outer Joins)或NOT
EXISTS. 例如:
SELECT …FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=’A’);
9.用EXISTS替换DISTINCT
当提交一个包含一对多表信?比如部门表和雇员?的查询时,避免在SELECT子句中用DISTINCT. 一般可以考虑用EXIST替换
例如:
10. 用烦引提高效?/strong>
索引是表的一个概念部分,用来提高索数据的效率Q实际上ORACLE使用了一个复杂的自^衡B-treel构Q通常通过索引查询数据比全表扫描要快,?
ORACLE扑և执行查询和Update语句的最佌\径时Q?ORACLE优化器将使用索引Q?
同样在联l多个表时用烦引也可以提高效率Q另一个用烦引的好处是,它提供了主键(primary key)的唯一性验证,除了那些LONG或LONG
RAW数据cd, 你可以烦引几乎所有的? 通常, 在大型表中用烦引特别有? 当然,你也会发?
在扫描小表时,使用索引同样能提高效率,虽然使用索引能得到查询效率的提高,但是我们也必L意到它的代h.
索引需要空间来存储Q也需要定期维护,每当有记录在表中增减或烦引列被修ҎQ烦引本w也会被修改Q这意味着每条记录的INSERT , DELETE ,
UPDATEؓ此多付出4 , 5 ơ的盘I/OQ?因ؓ索引需要额外的存储I间和处理,那些不必要的索引反而会使查询反应时间变?
注:定期的重构烦引是有必要的.
11. 避免在烦引列上用计?/strong>
WHERE子句中,如果索引列是函数的一部分Q优化器不使用索引而用全表扫? 举例Q?
12. ?gt;=替代>
]]>
result := 'IBM';
result := 'Microsoft';
result := 'Hewlett Packard';
result := 'Gateway';
decode 函数会挨个匹配supplier_id 的?
常见问题Q?/span>
?
?nbsp;yrs_of_service >= 1 and < 5 q回0.04
如果 yrs_of_service > 5
q回 0.06
If number = 0, then sign returns 0.
If number
> 0, then sign returns 1.
sign(-23)
would
return -1
sign(0.001)
would
return -1
sign(0)
would
return 0
sign(0.001)
would
return 1
sign(23)
would
return 1
sig(23.601)
trunc(125.815)
would return 125
trunc(125.815, 0)
would return 125
trunc(125.815, 1)
would return 125.8
trunc(125.815, 2)
would return 125.81
trunc(125.81,
3)
would return 125.81
trunc(-125.815, 2)
would return -125.81
trunc(125.815, -1)
would return 120
trunc(125.815, -2)
would return 100
trunc(125.81,
-3)
would return 0
]]>
对于rownum来说它是oraclepȝ序分配Z查询q回的行的编Pq回的第一行分配的?/span>1Q第二行?/span>2Q依此类推,q个伪字D可以用于限制查询返回的总行敎ͼ而且rownum不能以Q何表的名UC为前~?/span>
举例说明Q?/span>
例如表:student(学生)表,表结构ؓQ?/span>
ID char(6) --学号
name VARCHAR2(10) --姓名
/*
Formatted on 2008/09/24 09:15 (Formatter Plus v4.8.7) */
CREATE TABLE
student (ID CHAR(6), NAME VARCHAR2(100));
INSERT INTO student
VALUES ('200001', '张一');
INSERT INTO student
VALUES ('200002', '王二');
INSERT
INTO student
VALUES ('200003', '李三');
INSERT
INTO student
VALUES ('200004', '赵四');
COMMIT ;
(1)
rownum 对于{于某值的查询条g
如果希望扑ֈ学生表中W一条学生的信息Q可以?/span>rownum=1作ؓ条g。但是想扑ֈ学生表中W二条学生的信息Q?/span>rownum=2l果查不到数据。因?/span>rownum都是?/span>1开始,但是1以上的自然数?/span>rownum做等于判断是时认为都?/span>false条gQ所以无法查?/span>rownum = nQ?/span>n>1的自然数Q?/span>
SQL> select
rownum,id,name from student where rownum=1;Q可以用在限制返回记录条数的?
方,保证不出错,如:隐式游标Q?/span>
SQL> select
rownum,id,name from student where rownum=1;
ROWNUM ID NAME
----------
------ ---------------------------------------------------
1
200001 张一
SQL> select
rownum,id,name from student where rownum =2;
ROWNUM ID NAME
----------
------ ---------------------------------------------------
Q?/span>2Q?/span>rownum对于大于某值的查询条g
如果xCW二行记录以后的
记录Q当使用rownum>2是查不出记录的,
原因是由?/span>rownum是一个L?/span>1开始的伪列Q?/span>Oracle 认ؓrownum> n(n>1的自然数)q种条g依旧不成立,所以查不到记录
SQL> select rownum,id,name from student where rownum >2;
ROWNUM
ID NAME
---------- ------
---------------------------------------------------
那如何才能找到第二行以后的记
录呀。可以用以下的子查询方法来解决。注意子查询中的rownum必须要有别名Q否则还是不会查录来Q这是因?/span>rownum不是某个表的列,如果不v别名的话Q无法知?/span>rownum是子查询的列q是L询的列?/span>
SQL>select *
from(select rownum no ,id,name from student) where no>2;
NO ID NAME
---------- ------
---------------------------------------------------
3 200003
李三
4 200004 赵四
SQL> select * from(select rownum,id,name from student)where
rownum>2;
ROWNUM ID NAME
---------- ------
---------------------------------------------------
Q?/span>3Q?/span>rownum对于于某值的查询条g
如果x到第三条记录以前的记
录,当?/span>rownum<3是能得到两条记录
的。显?/span>rownum对于rownum<nQ?/span>(n>1的自然数Q的条g认ؓ是成立的Q所以可以找到记录?/span>
SQL> select rownum,id,name from student where rownum <3;
ROWNUM ID NAME
---------- ------
---------------------------------------------------
1 200001 张一
2 200002 王二
lg几种情况Q可能有时候需?
查询rownum在某区间的数据,那怎么办呀从上可以看出rownum对小于某值的查询条g是h?/span>true的,rownum对于大于某值的查询条g直接认ؓ?/span>false的,但是可以间接的让它{为是true的。那必M用子查询。例如要查询rownum在第二行到第三行之间的数据,包括W二行和W三行数据,那么我们只能写以下语句,先让它返回小于等?
三的记录行,然后在主查询中判断新?/span>rownum的别?
列大于等于二的记录行。但是这L操作会在大数据集中媄响速度?/span>
SQL> select *
from (select rownum no,id,name from student where rownum<=3 ) where
no >=2;
NO ID NAME
---------- ------
---------------------------------------------------
2 200002
王二
3 200003 李三
Q?/span>4Q?/span>rownum和排?/span>
Oracle中的rownum的是在取数据的时候生的序号Q所以想Ҏ定排序的数据L定的rowmun行数据就必须注意了?/span>
SQL> select
rownum ,id,name from student order by name;
ROWNUM ID NAME
----------
------ ---------------------------------------------------
3
200003 李三
2
200002 王二
1
200001 张一
4
200004 赵四
可以看出Q?/span>rownumq不是按?/span>name列来生成的序受系l是按照记录插入时的序l记录排的号Q?/span>rowid也是序分配的。ؓ了解册个问题,必须使用子查?/span>
SQL> select rownum ,id,name from (select * from student order
by name);
ROWNUM ID NAME
---------- ------
---------------------------------------------------
1 200003
李三
2 200002 王二
3 200001 张一
4
200004 赵四
q样成了按name排序Qƈ且用rownum标出正确序号Q有到大)?/span>
W者在工作中有一上百万条记录的表Q在jsp面中需对该表进行分|C, 便考虑?/span>rownum来作Q下面是具体Ҏ(每页
昄20?/span>)Q?/span>
“select *
from tabname where rownum<20 order by name" 但却发现oracle却不能按自己的意愿来执行Q而是先随?/span>
?/span>20条记录,然后?/span> order byQ后l咨?/span>oracle,?/span>rownum实pP想用的话Q只能用子查?/span> 来实现先排序Q后
rownumQ方法如下:
"select * from (select * from
tabname order by name) where rownum<20",但这样一来,效率会较低很多?/span>
后经W者试验,只需?/span>order by 的字D上加主键或索引卛_?/span>oracle先按 该字D|序,然后?/span>rownumQ方法不变:
“select * from tabname where rownum<20 order by name"
补充Q我们正常分|如下Q?/span>order by 主键Q在最里面的那一层。非主键字段同样?/span> 加烦引)Q?/span>
/* Formatted on 2008/09/24 12:14 (Formatter Plus v4.8.7) */
SELECT
*
FROM (SELECT tmp.*, ROWNUM rn
FROM (SELECT *
FROM student
WHERE 1 = 1
ORDER
BY NAME DESC) tmp
WHERE 1 = 1 AND ROWNUM <= 3)
WHERE 1
= 1 AND rn >= 2
(5) 取得某列中第N大的?/span>
select
column_name from
(select table_name.*,dense_rank() over (order by
column desc) rank from table_name)
where rank = &NQ?/span>
/* Formatted on 2008/09/24 12:30
(Formatter Plus v4.8.7) */
SELECT *
FROM (SELECT student.*,
DENSE_RANK () OVER (ORDER BY ID DESC) RANK
FROM student)
WHERE
RANK = 2
(6)假如要返回前5条记录:
select
* from tablename where rownum<6;(或是rownum <= 5 或是rownum
!= 6)
假如要返回第5-9条记录:
/* Formatted on 2008/09/24 12:34 (Formatter Plus
v4.8.7) */
SELECT *
FROM student
WHERE ROWNUM < 4
MINUS
SELECT
*
FROM student
WHERE ROWNUM < 2
order by
name
选出l果后用name排序昄l果?/span>(先选再排序)
注意Q只能用以上W号(<?/span><=?/span>!=)?/span>
(7)select
* from tablename where rownum != 10;q回的是前9条记录?/span>
不能用:>,>=,=,Between...and。由?/span>rownum是一个L?/span>1开始的伪列Q?/span>Oracle 认ؓq种条g 不成立,查不到记?/span>.
?
外,q个Ҏ更快Q?/span>
select
* from (
select rownum r,a from yourtable
where rownum <= 20
order by name )
where r > 10
q样取出W?/span>11-20条记?/span>!(先选再排序再?/span>)
要先排序再选则ȝselect嵌套Q内层排序外层选?/span>
rownum是随着l果集生成的Q一旦生成,׃会变化了Q同?/span>,生成的结?
是依ơ递加的,没有1永q不会有2!
rownum 是在 查询集合产生的过E中产生的伪列,q且如果where条g中存?/span> rownum 条g的话Q则:
1Q?/span> 假如 判定条g是常量,则:
只能 rownum = 1,
<= 大于1 的自然数Q?/span> = 大于1 的数是没有结果的Q?/span> 大于一个数也是没有l果?/span>
?/span> 当出C?/span> rownum 不满x件的时候则 查询l束 this
is stop key!
2: 当判
定g是常量的时?/span>
若条件是 = var , 则只有当 var ?/span>1 的时候才满条gQ这个时候不存在 stop key ,必须q行 full scan ,Ҏ个满_?/span>where条g的数据进行判?/span>
选出一行后才能去?/span>rownum=2的行……
ID是主键,PID是父节点IDQIND是排序字D,NAME是节点名U。初始化几条试数据?/p>
ID | PID | IND | NAME |
---|---|---|---|
1 | 0 | 1 | 根节?/td> |
2 | 1 | 1 | 一U菜? |
3 | 1 | 2 | 一U菜? |
4 | 1 | 2 | 一U菜? |
5 | 2 | 1 | 一U?? |
6 | 2 | 2 | 一U?? |
7 | 4 | 1 | 一U?? |
8 | 4 | 2 | 一U?? |
9 | 4 | 3 | 一U?? |
10 | 4 | 0 | 一U?? |
一、基本用:
在Oracle中,递归查询要用到start with 。。。。connect by prior。。?/p>
具体格式是:
ID | PID | IND | NAME |
---|---|---|---|
1 | 0 | 1 | 根节?/td> |
2 | 1 | 1 | 一U菜? |
5 | 2 | 1 | 一U?? |
6 | 2 | 2 | 一U?? |
3 | 1 | 2 | 一U菜? |
4 | 1 | 2 | 一U菜? |
7 | 4 | 1 | 一U?? |
8 | 4 | 2 | 一U?? |
9 | 4 | 3 | 一U?? |
10 | 4 | 0 | 一U?? |
我们从结果中可以看到Q记录已l是按照树Şl构q行排列了,但是现在有个新问题,如果我们有这L需求,是不但要求l果按照树Şl构昄Q还要根据ind字段在每一个分支内q行排序Q这个问题怎么处理呢?我们可能很自然的惛_如下语句Q?/p>
l果如下Q?/p>
ID | PID | IND | NAME |
---|---|---|---|
1 | 0 | 1 | 根节?/td> |
2 | 1 | 1 | 一U菜? |
5 | 2 | 1 | 一U?? |
6 | 2 | 2 | 一U?? |
4 | 1 | 2 | 一U菜? |
10 | 4 | 0 | 一U?? |
8 | 4 | 2 | 一U?? |
9 | 4 | 3 | 一U?? |
7 | 4 | 1 | 一U?? |
3 | 1 | 2 | 一U菜? |
q显然不是我们想要的l果Q那下面的这个语句呢Q?/p>
l果如下Q?/p>
ID | PID | IND | NAME |
---|---|---|---|
1 | 0 | 1 | 根节?/td> |
2 | 1 | 1 | 一U菜? |
5 | 2 | 1 | 一U?? |
6 | 2 | 2 | 一U?? |
4 | 1 | 2 | 一U菜? |
10 | 4 | 0 | 一U?? |
8 | 4 | 2 | 一U?? |
9 | 4 | 3 | 一U?? |
7 | 4 | 1 | 一U?? |
3 | 1 | 2 | 一U菜? |
q个l果看似对了Q但׃一U菜?节点下有一个节点的ind=0Q导致一U菜?被拍C3下面。如果想使用cMq样的语句做到各分支内排序,则需要找C个能够准描q菜单别的字段Q但是对于示例表来说Q不存在q么一个字Dc?/p>
那我们如何实现需求呢Q其实Oracle9以后Q提供了一U排?#8220;order siblings by”可以实现我们的需求,用法如下Q?/p>
l果如下Q?/p>
ID | PID | IND | NAME |
---|---|---|---|
1 | 0 | 1 | 根节?/td> |
2 | 1 | 1 | 一U菜? |
5 | 2 | 1 | 一U?? |
6 | 2 | 2 | 一U?? |
3 | 1 | 2 | 一U菜? |
4 | 1 | 2 | 一U菜? |
10 | 4 | 0 | 一U?? |
7 | 4 | 1 | 一U?? |
8 | 4 | 2 | 一U?? |
9 | 4 | 3 | 一U?? |
q样一来,查询l果完全符合我们的要求了?/p>
至于在Oracle8以前版本Q或者其他数据库中如何实现类似的功能Q希望大家来指教下,谢谢?/p>
在java对oracle的操作中Q日期字D|很头疼的事情Q其实仔l研I一下也q不难掌握?
举个例子来说明:
?book 中有name varchar2(20)//书籍名称,buydate Date //购买日期 两个字段?/p>
已经创徏了数据库q接Connection conn;
Ҏ一、用java.sql.Date实现比较单的yyyy-mm-dd格式日期?/strong>
java.sql.Date不支持时间格式。切C要用new java.sql.Date(int year,int month,int date),因ؓq要处理旉差问题?/p>
Ҏ二、用java.sql.Timestamp,同上不用new Timestamp(....)
Ҏ三、用oracle 的to_date内置函数
?oracle日期格式参数 含义说明
d: 一周中的星期几
day: 天的名字Q用空格填充到9个字W?nbsp;
dd: 月中的第几天
ddd: q中的第几天
dy: 天的写名
iw: ISO标准的年中的W几?nbsp;
iyyy: ISO标准的四位年?nbsp;
yyyy: 四位q䆾
yyy,yy,y: q䆾的最后三位,两位Q一?nbsp;
hh: 时Q按12时?nbsp;
hh24: 时Q按24时?nbsp;
mi: ?nbsp;
ss: U?nbsp;
mm: ?nbsp;
mon: 月䆾的简?nbsp;
month: 月䆾的全?nbsp;
w: 该月的第几个星期
ww: q中的第几个星期
DECLARE @dtStartDate DATETIME,
@dtEndDate DATETIME,
@dtDate DATETIME,
@i INTEGER
SET @dtEndDate = '5/5/1997'
SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1) AS
VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + ' 23:59:59' AS DATETIME))
SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)
-- Get all months into the first table
SET @i = 0
WHILE (@i < 12)
BEGIN
SET @dtDate = DATEADD(mm, -1 * @i, @dtEndDate)
INSERT INTO @tblMonths SELECT CAST(YEAR(@dtDate) AS VARCHAR(4)) + '-' +
CASE
WHEN MONTH(@dtDate) < 10
THEN '0' + CAST(MONTH(@dtDate) AS VARCHAR(2))
ELSE CAST(MONTH(@dtDate) AS VARCHAR(2))
END AS sMonth
SET @i = @i + 1
END
-- Get all clients who had sales during that period into the "y" table
INSERT INTO @tblCustomers
SELECT DISTINCT
c.CustomerID,
c.CompanyName,
c.ContactName
FROM Customers c
INNER JOIN Orders o ON c.CustomerID = o.CustomerID
WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate
INSERT INTO @tblFinal
SELECT m.sMonth,
c.CustomerID,
c.CompanyName,
c.ContactName,
0
FROM @tblMonths m CROSS JOIN @tblCustomers c
UPDATE @tblFinal SET
mSales = mydata.mSales
FROM @tblFinal f INNER JOIN
(
SELECT c.CustomerID,
CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +
CASE WHEN MONTH(o.OrderDate) < 10
THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))
ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))
END AS sMonth,
SUM(od.Quantity * od.UnitPrice) AS mSales
FROM Customers c
INNER JOIN Orders o ON c.CustomerID = o.CustomerID
INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate
GROUP BY
c.CustomerID,
CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +
CASE WHEN MONTH(o.OrderDate) < 10
THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))
ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))
END
) mydata on f.CustomerID = mydata.CustomerID AND f.sMonth =
mydata.sMonth
SELECT f.sMonth,
f.CustomerID,
f.CompanyName,
f.ContactName,
f.mSales
FROM @tblFinal f
ORDER BY
f.CompanyName,
f.sMonth
5, N补零
q?里介l其他一些可帮助提高 SQL 查询效率的常用技术。假设您按区域Ҏ有销售h员进行分lƈ他们的销售额q行计Q但是您只想要那些数据库中标Cؓ处于zd状态的销售h员。您可以?区域寚w售h员分l,q?HAVING 子句消除那些未处于活动状态的销售h员,也可以在 WHERE 子句中执行此操作。在 WHERE 子句中执行此操作会减需要分l的行数Q所以比?HAVING 子句中执行此操作效率更高。HAVING 子句中基于行的条件的{选会强制查询寚w些在 WHERE 子句中会被去除的数据q行分组?/font>
?一个提高效率的技巧是使用 DISTINCT 关键字查找数据行的单独报表,来代替?GROUP BY 子句。在q种情况下,使用 DISTINCT 关键字的 SQL 效率更高。请在需要计聚合函敎ͼSUM、COUNT、MAX {)的情况下再?GROUP BY。另外,如果您的查询L自己q回一个唯一的行Q则不要使用 DISTINCT 关键字。在q种情况下,DISTINCT 关键字只会增加系l开销?/font>
1?nbsp;׃n池又׃部分构成Q共享SQL区和数据字典~冲区。共享SQLZ门存攄户SQL命oQ?span class="hilite1">oracle使用最q最用等优先U算法来更新覆盖Q数据字典缓冲区Qlibrary cacheQ存放数据库q行的动态信息。数据库q行一D|间后QDBA需要查看这些内存区域的命中率以从数据库角度Ҏ据库性能调优。通过执行下述语句查看Q?br />
select (sum(pins - reloads)) / sum(pins) "Lib Cache" from v$librarycache;
--查看׃nSQL区的重用率,最好在90Q以上,否则需要增加共享池的大?br />
select (sum(gets - getmisses - usage - fixED)) / sum(gets) "Row Cache" from v$rowcache;
--查看数据字典~冲区的命中率,最好在90Q以上,否则需要增加共享池的大?br />
2?nbsp; 数据~冲区:存放sqlq行l果抓取到的data blockQ?br />
SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads');
-- 查看数据库数据缓冲区的用情c查询出来的l果可以计算出来数据~冲区的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。命中率应该?0Q以上,否则需要增加数据缓冲区的大?br />
3?nbsp;日志~冲区:存放数据库运行生成的日志?br />
select name,value from v$sysstat where name in ('redo entries','redo log space requests');
--查看日志~冲区的使用情况。查询出的结果可以计出日志~冲区的甌p|率:甌p|率=requests/entriesQ申请失败率应该接近?Q否则说明日志缓冲区开讑֤,需要增?span class="hilite1">ORACLE数据库的日志~冲区?br />
二.Sql语句的执行步骤:
了解sql的执行步骤有利于更好的优化它们,每条sql语句执行旉要经历以下几步:
1. Create cursor Q?
2. Parse, if it is not already in the shared pool.Q?br />
3. Any query in the statement is processed.
4. Bind Variables
5. Execute.
6. If possible, the statement is parallelized.
7. Rows to be returned are fetched.
其中QParse—是最有优化潜力的阶段?br />
Cursor创徏后,oracle在share pool中寻找是否该sql语句已经存在Q若已经存在且已l被parsedQ则不需要再执行parseQ直接到下一步。若未在share pool中找刎ͼ则parse步一般需要执行下面步骤:
1. The statement is validated.
2. The data is validated.
3. Locks are allocated.
4. Privileges are verified.
5. The execution plan is determined.
6. The statement is loaded into the shared SQL area.
--parse有这么多步骤Q所以能利用sharepool中现成的parsel果很重要?/p>
? 如何提高share pool中Sql׃n率?
要实现sql׃nQ蟩qparse步骤Q有如下基本要求条gQ?br />
1. sql文本完全相同Q?br />
--uppercase and lowercase
--white space (spaces, tabs, carriage returns)
--comments
2.参考对象相?
--Referenced schema’s objects must be the same objects
3. l定变量相同
--Bind variables must match the same name and data type.Q所以对于格式相同?span id="S__699_ADDIV_1" onmouseover="S__699.SHOWFLOW('具体','1',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('具体','1',event);" onmouseout="S__699.hidden('1');;this.style.textDecoration='underline';" oncontentextmenu="return false">具体条g不同的sqlQ徏议经怋用变量来代替帔RQ以量使用重复sql代码Q避开parse阶段Q提高执行速度Q?br />
--tipQ?br />
--量使用存储q程Q尽量用变量代替常量,可以提高share pool׃n率,跌parse阶段Q提高效率?br />
四.什么是好的sql语句Q?br />
ȝZ下特征:
• 量使用 PL/SQL提高性能Q?PL/SQL可以sql语句块一ơ送给数据库服务器处理Q不用PL/SQL只能一句一句送?
• 量使用stored procedureQ降?span class="hilite1">oracle通过|络传输的数据量Qƈ能提高共享sql区域的重用率?br />
• 量使用packagesQ?Packages在第一ơ调用时能将整个?loadq内存,Ҏ高性能有帮助?
• 量使用cached sequences 来生成primary key Q提高主键生成速度和用性能?
• 很好地利用空_如用VARCHAR2 数据cd代替 CHAR{?br />
• 只在非常必要时才使用hintQ仅在对sql的执行计划非常肯定地要用hint时才使用?
五.Sql优化工具的介l:
sqlexpertQtoadQexplain-tableQPL/SQLQOEM{?br />
掌握一U,熟练使用卛_?br />
我的习惯Q看执行计划用sqlplus 的autotraceQ优化用sql expert?/p>
--Autotrace使用ҎQ?br />
1. DBA在db中创建plustrace 角色Q运行@?/sqlplus/admin/plustrce.sql
2. DBAl用戯予角Ԍgrant plustrace to username;
3. 用户创徏自己的plan_tableQ运行@?/rdbms/admin/utlxplan.sql?-以上是第一ơ用时需要进行的必要操作?br />
4. 用户sqlplusq接数据库,对会话进行如下设|:
Set autotrace -----off/on/trace[only]------explain/statisticsQ?br />
然后录入sql语句回R卛_查看执行计划—推荐;
或者用如下命o行:
Explain plan set statement_id=’myplan1’ for Your sql-statement;
然后查看用户自己的plan_table
--演示Sql-expert的用,q接到指定数据库Q输入sqlQ显C执行计划或者sql优化l果Q图形界面如下:
--psQ但我在使用中发现sql-expert的执行计划有时候显C得q不准确Q所以徏议以sqlplus中的为准。其sql优化倒很值得参考,有多U结果,用户可以自己试和选择?/p>
六.SQL优化技?br /> 在这斚wQ长期搞数据库应用开发的人应该更有经验,我这里大概ȝ一下自己遇到过的和搜集到的一些sql优化l验Q跟大家共同学习?br /> SQL语言是一U灵zȝ语言Q相同的功能可以使用不同的语句来实现Q但是语句的执行效率可能会很不相同的Q生产系l里l常跑的sql语句更要注意执行效率Q否则会占用大量pȝ资源Q带慢整个系l。SQL优化的实质就是在l果正确的前提下Q用优化器可以识别的语句Q充份利用烦引,执行q程中访问尽量少的数据块Q减表扫描的I/Oơ数Q尽?span id="S__699_ADDIV_3" onmouseover="S__699.SHOWFLOW('避免','3',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('避免','3',event);" onmouseout="S__699.hidden('3');;this.style.textDecoration='underline';" oncontentextmenu="return false">避免全表扫描和其他额外开销?br /> Sql优化Q?br /> 1?nbsp;先介l一?span class="hilite1">oracle数据库常用的两种优化器:RBOQrule-based-optimizerQ和CBO(cost-based-optimizer)。目前更多地采用CBO(cost-based-optimizer)Z开销的优化器。在CBO方式下,Oracle会根据表及烦引的状态信息来选择计划Q在RBO方式下,Oracle会根据自己内部设|的一些规则来军_选择计划Q例?span class="hilite1">oracle会根据以下优先来选择执行计划Q越靠前Qrank低Q越快)Q?/p>
RANK Access path
1 ROWID{于帔R
2 唯一键值或主键的聚连?
3 唯一键值或主键的哈希聚连?
4 整个复合索引{于帔R
5 唯一索引列等于常?br />
6 完全聚簇键等于同一个聚上的另一个表对应的聚键*
7 哈希聚簇键等于常?
8 完全聚簇键等于常?
9 整个非唯一l合索引{于帔R
10 非唯一索引q结
11 整个l合索引{于范围的?br />
12 l合索引的大部分前面的列{于帔R
13 索引列取值存在上限和下限或者烦引列LIKE "ABC%"Q范围限Ӟ
14 非唯一索引列取值存在上限和下限或者烦引列LIKE "ABC%"Q范围限Ӟ
15 唯一索引列或是常量(范围无限Ӟ
16 非唯一索引列或是常Q范围无限制Q?br />
17 非烦引列的等D?sort/merge join)
18 单一索引列的最大或最?br />
19 ORDER BY整个索引
20 全表扫描
2?nbsp;创徏索引Q创建烦引一般有以下两个目的Q维护被索引列的唯一性和提供快速访问表中数据的{略?br />
索引创徏原则Q?br />
--在select操作占大部分的表上创建烦引;
--在where子句中出现最频繁的列上创建烦引;
--在选择性高的列上创建烦引(补充索引选择性,最高是1QegQprimary keyQ?br />
--复合索引的主列应该是最有选择性的和where限定条g最常用的列Qƈ以此cLW二?#8230;…?br />
--于5M的表Q最好不要用烦引来查询Q表小Q越适合用全表扫描?/p>
索引使用原则Q?br />
--查询l果是所有数据行?%以下Ӟ使用index查询效果最好;
--where条g中经常用到表的多列时Q用复合烦引效果会好于几个单列索引。因为当sql 语句所查询的列Q全部都出现在复合烦引中Ӟ此时׃ Oracle 只需要查询烦引块卛_获得所有数据,当然比用多个单列烦引要快得多;
--索引利于selectQ但对经常insertQdelte其update的表Q会降低效率?/p>
egQ试比较下面两条SQL语句(emp 表的deptno列上建有ununique index)Q?br />
语句AQSELECT dname, deptno FROM dept WHERE deptno NOT IN
(SELECT deptno FROM emp);
语句BQSELECT dname, deptno FROM dept WHERE NOT EXISTS
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);
q两条查询语句实现的l果是相同的Q但是执行语句A的时候,ORACLE会对整个emp表进行扫描,没有使用建立在emp表上的deptno索引Q执行语句B的时候,׃在子查询中用了联合查询Q?span class="hilite1">ORACLE只是对emp表进行的部分数据扫描Qƈ利用了deptno列的索引Q所以语句B的效率要比语句A的效率高。我的测试结果:(当emp表有37M时的试)Q?br />
SQL> SELECT dname, deptno FROM dept WHERE deptno NOT IN
(SELECT deptno FROM emp);
DNAME DEPTNO
-------------- ----------
OPERATIONS 40
Elapsed: 00:00:01.08
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 TABLE ACCESS (FULL) OF 'DEPT'
3 1 TABLE ACCESS (FULL) OF 'EMP'
Statistics
----------------------------------------------------------
0 recursive calls
31 db block gets
4635 consistent gets
1 physical reads
0 redo size
541 bytes sent via SQL*Net to client
550 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> SELECT dname, deptno FROM dept WHERE NOT EXISTS
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);
DNAME DEPTNO
-------------- ----------
OPERATIONS 40
Elapsed: 00:00:00.30
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 TABLE ACCESS (FULL) OF 'DEPT'
3 1 INDEX (RANGE SCAN) OF 'IND_EMP_DEPTNO' (NON-UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
12 db block gets
19 consistent gets
0 physical reads
144 redo size
541 bytes sent via SQL*Net to client
550 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
3Q?nbsp;索引常用cdQ按存储方式分ؓQB-tree QbitmapQreverse key index
?nbsp;B-reeQ最常用的一U,又可以分为primary, unique,nonuniqueQcomposite,cluster{?br />
?nbsp;bitmap适用情况Q?br />
--该列重复值很高(egQ性别列、分数列ABCU等Q,最好该列有not null的限Ӟ
--bitmap对大表效果好Q且很节省烦引空_
--适合q发度低的表Q因为其数据更新时会锁住整个bitmap blockQ?br />
--使用bitmap索引Ӟ需要加hint强制使用Q应该是oracle一个bugQ?br />
?nbsp;Reverse索引Q适用于序列生成的数字列,会将index key列值倒序存放Q尤其表的更改ƈ发度又比较高Ӟ更适合用reverse索引Q这样可以将怼值的行分散到索引的多个叶子节点,降低冲突Q提高性能?br />
Ҏ应用需求在适当列徏合适的索引?/p>
4、 Oracle 要用一个烦引,有一些基本要求条Ӟ
----where 子句中的q个字段Q必L复合索引的第一个字D;
egQ一个烦引是?f1, f2, f3的次序徏立的Q若where 子句?f2 = : var2, 则因?f2 不是索引的第1个字D,无法使用该烦引?br />
---- where 子句中的q个字段Q不应该参与M形式的计:M对列的操作都导致表扫描Q它包括数据库函数、计表辑ּ{等Q查询时要尽可能操作移至等号右辏V?br />
----应尽量熟悉各U操作符?Oracle 是否使用索引的媄响:以下q些操作会显式(explicitlyQ地L Oracle 使用索引Q?is null ; is not null ; not in; !=; like ; numeric_col+0;date_col+0; char_col||’ ’; to_char; to_numberQto_date {?br />
EgQ?br />
Select jobid from mytabs where isReq='0' and to_date (updatedate) >= to_Date ( '2001-7-18', 'YYYY-MM-DD')Q?-updatedate列的索引也不会生效?
5、烦引不是越多越好。特别是大量从来或者几乎不用的索引Q对pȝ只有损害。OLTPpȝ每表过5个烦引即会降低性能Q?nbsp; 而且在一个sql 中, Oracle 从不能用超q?5个烦引?
索引对select有正面效果,但对insertQdelete其是update有负面效果,会媄响速度Q烦引越多,影响大。所?span class="hilite1">oracle工具sqlldr倒入数据Ӟ好的做法是先建好表结构,再倒入数据Q最后才建烦引,以提高数据倒入的速度Q?span class="hilite1">oracle工具import默认是先倒入数据Q然后才建烦引。所以徏索引时要充分考虑该表的主要应用?br />
TipsQ?l常做insertQdelete其是update的表最好定期exp/imp表数据,整理数据Q降低碎片(~点Q要停应用,以保持数据一致性,不实 用)Q有索引的最好定期rebuild索引Qrebuild期间只允许表的select操作Q可在数据库较空闲时间提交)Q以降低索引片Q提高效率;
6、何旉合使用全表扫描Q?br />
--表Q仅有几个data block的表Q?M以下Q;
--Ҏ据行的选择率高?0%时可考虑用全表扫描(如有1000行记录,一ơ选出200行以上)
7Q选择联合查询的联合次序。联合查询分?U:merge join,nested loop,hash joinQ这里讲的是nested loop的联合情况(后面实际案例1的优化就属于此类Q;
考虑下面的例子:
SELECT stuff FROM taba a, tabb b, tabc c
WHERE a.acol between :alow and :ahigh
AND b.bcol between :blow and :bhigh
AND c.ccol between :clow and :chigh
AND a.key1 = b.key1
AMD a.key2 = c.key2;
q?个SQL例子中,E序员首先需要选择要查询的主表Q因Z表要q行整个表数据的扫描Q所以主表应该数据量最,所以例子中表A的acol列的范围应该比表 B和表C相应列的范围。内外表的选择可由公式Q外层表中的匚w行数*内层表中每一ơ查扄ơ数定Q乘U最ؓ最x案?/p>
8、用UNION ALL代替UNIONQ?br /> UNION是最常用的集操作Q多个记录集联l成为单个集Q对q回的数据行有唯一性要求,所?span class="hilite1">oracle需要进行SORT UNIQUE操作Q与使用distinct时操作类|Q如果结果集又比较大Q则操作会比较慢Q?br /> UNION ALL操作不排除重复记录行Q所以会快很多,如果数据本n重复行存在可能性较时Q用union all会比用union效率高很多!
9Q?nbsp;避免在SQL里用PL/SQL功能调用Q?br />
PL/SQL块有利于提高重复使用代码Q但是如果合在SQL语句中,反而会降低效率。EgQ?br />
US$()Z货币转换的PL/SQL
Sql: select name,US$(amount,currency) from salary where US$(amount,currency)>1000;
该sql效率低下Q因为合PL/SQL和sqlӞoracle使用的机制不同,执行Ӟoracle调用分成两个组Ӟ用带有赋值变量的SQL语句代替功能调用Q和对功能调用的PL/SQL块:
卻I
select name,:a1 from salary where :a2>1000;
?br />
begin
:a1:=US$(:amount,:currency);
end;
对salary表里的每一行执行PL/SQL两次Q效率大大降低?/p>
10 子查询中慎重使用IN或者NOT IN语句Q用where (NOT) exists的效果要好的多。IN、OR子句怼使烦引失效,可以考虑把子句拆开Q拆开的子句中量包含索引?br />
11慎重使用视图的联合查询,其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些?/p>
12 ORACLE?供的DBMS_SHARED_POOLE序可以帮助E序员将某些l常使用的存储过E?#8220;?#8221;在SQLZ而不被换出内存,E序员对于经怋用ƈ且占用内存较 多的存储q程“?#8221;到内存中有利于提高最l用L响应旉。一定要认非常有必要时才采用这个方法,否则对系l只有坏的媄响,会降低内存利用率?br />
(execute DBMS_SHARED_POOL.KEEP('APPOWNER.ADD_CLIENT','P');
QP代表PROCEDURESQC代表CURSORSQ?
13. 从物理存储方面降低竞争,提高索引效率Q将索引和数据分开不同的表I间存放Q以减少I/O竞争Q尽量将索引、数据表I间从物理底y分开是数据库前期?理设计工作的重要部分Q。D例:九七数据库里的TB表(镉KcacheQ仅几十行数据,q发度高Q更新频J,分多个block存放Q降低block I/O竞争Q?/p>
14Q加hint强制使用索引
有时?span class="hilite1">oracle自动判断的CBO信息不能令h满意Ӟ需要我们手工加hint来强制sql语句得到我们惌的执行计划?br />
Hint的基本用方法:
----紧跟DMLQselectQinsertQdeleteQupdateQ之后:/*+hint_content*/Q?*?之间不能有空|或者用--+Q此行后面均为hint内容Q?br />
----一句sql只能有一个hintQ但里面可以有多层,egQ?*+hint1,hint2…*/Q?br />
----sql语句中若使用了别?aliase)Q则hint里面也必M用别名?br />
--不要对view查询加hintQ无效?br />
TipQ尽量少用hintQ因为随着数据变化Q可能加hint的执行计划逐渐变的不再是最优;加hint的维护成本较高;
15Q用session/transactionU别的时表会大大提高中间处理的速度Q?br />
---临时表只Ҏsession或者transaction可见Q关闭session或者退出transactionӞ临时表自动被清理dropQ?br />
---其他session/transaction可以建同名的temporary tableQ用户只对自qtemp table操作Q?br />
---临时表用temp表空_此类表的DML操作不生redo logQ只产生undo log
---可以在其上徏indexQindex也一htemporary的,生命阶段同temp table?br />
create global temporary table tab_name(….)Q?/p>
l语Q?br /> Oracle 是否真正使用索引Q用烦引是否真正有效,q是必须q行实地的测验。合理的做法是,Ҏ写的复杂?sql, 在将它写入应用程序之前,先在产品数据库上做一ơexplainQ获得对?sql 的解析,明确看到 Oracle 是如何执行该sql 的,q进行适当优化调整Q?br /> 另外Q即使是相同的sql语句Q也会因的大等原因造成执行计划的不同,所以一定要具体情况具体分析Q?如果l常?explain, ׃发现Q喜爱写复杂?sql q不是个好习惯,因ؓq分复杂的sql 其解析计划往往不尽如h意。事实上Q将复杂?sql 拆开Q有时候会极大地提高效率,因ؓ能获得很好的优化?/p>
赉|?nbsp;
2004.5.26 定稿
实际案例:
1?select 'x' from dh where dhso in (select ogso from og where ogid = 21097023 and ogzt='VALID') and dhcz = 18 and dhzt<>'OVER'Q?br />
执行情况Qno rows selected Elapsed: 00:07:05.98
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 VIEW
2 1 SORT (UNIQUE)
3 2 NESTED LOOPS
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'DH'
5 4 INDEX (RANGE SCAN) OF 'IND_DHCZ_DHZT' (NON-UNIQUE)
6 3 TABLE ACCESS (BY INDEX ROWID) OF 'OG'
7 6 INDEX (UNIQUE SCAN) OF 'PK_OGID_OGSO' (UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
421027 consistent gets
15181 physical reads
1000 redo size
181 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
原语句用7?U完成,使用sqlexpert优化后选取的一个新语句如下Q出l果仅用8U!
select /*+ ALL_ROWS */ 'x' from dh
where EXISTS (SELECT 'X' from og WHERE ogid = 21097023 and ogzt = 'VALID' AND ogso = dhso) and dhcz = 18 and dhzt <> 'OVER'Q?br />
执行情况Q?nbsp; no rows selected Elapsed: 00:00:08.23
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: ALL_ROWS (Cost=119 Card=55
Bytes=3410)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'DH' (Cost=2 Card=1 Bytes
=31)
2 1 NESTED LOOPS (Cost=119 Card=55 Bytes=3410)
3 2 SORT (UNIQUE)
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'OG' (Cost=6 Card=5
5 Bytes=1705)
5 4 INDEX (RANGE SCAN) OF 'PK_OGID_OGSO' (UNIQUE) (Cos
t=2 Card=2191)
6 2 INDEX (RANGE SCAN) OF 'IND_DHSO' (NON-UNIQUE) (Cost=1
Card=2018)
Statistics
----------------------------------------------------------
16 recursive calls
0 db block gets
10 consistent gets
1 physical reads
0 redo size
181 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
2、select GGZT,GGXX,GGSJ,GGRQ,GGLR,GGGH,GGDH,GGBZ,GGID
from GG where GGRQ>='20040325'
and GGRQ<='20040325' and GGID>8673 and GGZT='VALID' and GGID in
(select GFGG from GF,GB where GFGG=GBGG
and ((GFGW=1 and GFQX>='003' and GBLX='001' and GBDW=104)
or (GFGW=118 and GFQX>='000' and GBLX='002' and GBDW=102)))
order by GGID DESC;
--联合查询三个表QGG 1MQ?nbsp; GB 2MQ?nbsp; GF 2MQ? 用了索引反而慢Q又费cpuQ优化后Ҏ全表扫描:
执行情况Q?br />
no rows selected
Elapsed: 00:00:18.57
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (ORDER BY)
2 1 VIEW
3 2 SORT (UNIQUE)
4 3 CONCATENATION
5 4 NESTED LOOPS
6 5 NESTED LOOPS
7 6 TABLE ACCESS (BY INDEX ROWID) OF 'GB'
8 7 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON-U
NIQUE)
9 6 TABLE ACCESS (BY INDEX ROWID) OF 'GF'
10 9 INDEX (RANGE SCAN) OF 'IND_GFGW' (NON-UNIQUE
)
11 5 TABLE ACCESS (BY INDEX ROWID) OF 'GG'
12 11 INDEX (UNIQUE SCAN) OF 'PK_GGID' (UNIQUE)
13 4 NESTED LOOPS
14 13 NESTED LOOPS
15 14 TABLE ACCESS (BY INDEX ROWID) OF 'GB'
16 15 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON-U
NIQUE)
17 14 TABLE ACCESS (BY INDEX ROWID) OF 'GF'
18 17 INDEX (RANGE SCAN) OF 'IND_GFGW' (NON-UNIQUE
)
19 13 TABLE ACCESS (BY INDEX ROWID) OF 'GG'
20 19 INDEX (UNIQUE SCAN) OF 'PK_GGID' (UNIQUE)
Statistics
----------------------------------------------------------
243 recursive calls
0 db block gets
346554 consistent gets
20 physical reads
0 redo size
534 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
8 sorts (memory)
0 sorts (disk)
0 rows processed
select /*+ full(gg) */ GGZT,GGXX,GGSJ,GGRQ,GGLR,GGGH,GGDH,GGBZ,GGID
from GG where GGRQ>='20040325'
and GGRQ<='20040325' and GGID>8673 and GGZT='VALID' and GGID in
(select /*+ full(gf) */ GFGG from GF,GB where GFGG=GBGG
and ((GFGW=1 and GFQX>='003' and GBLX='001' and GBDW=104)
or (GFGW=118 and GFQX>='000' and GBLX='002' and GBDW=102)))
order by GGID DESC;
执行情况Q?br />
no rows selected
Elapsed: 00:00:07.96
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=25 Card=1 Bytes=715)
1 0 SORT (ORDER BY) (Cost=25 Card=1 Bytes=715)
2 1 HASH JOIN (SEMI) (Cost=22 Card=1 Bytes=715)
3 2 TABLE ACCESS (FULL) OF 'GG' (Cost=3 Card=1 Bytes=702)
4 2 VIEW OF 'VW_NSO_1' (Cost=18 Card=1 Bytes=13)
5 4 HASH JOIN (Cost=18 Card=1 Bytes=62)
6 5 TABLE ACCESS (BY INDEX ROWID) OF 'GB' (Cost=4 Card
=1041 Bytes=32271)
7 6 BITMAP CONVERSION (TO ROWIDS)
8 7 BITMAP OR
9 8 BITMAP CONVERSION (FROM ROWIDS)
10 9 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON
-UNIQUE) (Cost=1)
11 8 BITMAP CONVERSION (FROM ROWIDS)
12 11 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON
-UNIQUE) (Cost=1)
13 5 TABLE ACCESS (FULL) OF 'GF' (Cost=13 Card=1213 Byt
es=37603)
Statistics
----------------------------------------------------------
390 recursive calls
0 db block gets
82 consistent gets
4 physical reads
0 redo size
534 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed