2) 连接符OR、IN、AND、以及=、<=、>=等前后加上一个空格。当语句中涌现括号时,括号的两边不留空格。
3) “不即是”统一利用"<>"。虽然"!="和"<>"是等价的,为了统一,不即是一律利用"<>"表示。
4) 关键字、保留字预留到左边起始位置,一行有多列,超过80 个字符时,基于列对齐原则,采取下行缩进。

5) SQL中的字符类型数据该当统一利用单引号。特殊对纯数字的字串,必须用单引号,否则会导致内部转换而引起性能问题或索引失落效问题。利用trim(),lower()等函数格式化匹配条件。
6) 对付非常繁芜的sql(特殊是有多层嵌套,带子句或干系查询的),该当先考虑是否设计不当引起的。对付一些繁芜SQL可以考虑利用程序实现。
7) SQL语句用大写,由于oracle总是先解析SQL语句,把小写的字母转换成大写的再实行。
例如:
SELECT A.ORDER_ID,A.ORDER_CONTENT
FROM CRM_ORDER A,CRM_PRODUCT B
WHERE A.ORDER_ID = B.FK_ORDER_ID
AND A.ORDER_ID = 'A001'
/关键字、保留字、函数左对齐、首字母只管即便大写/
1.2 SELECT语句的格式标准SELECT Column_name1,Column_name2
INTO :Parameter1,:Parameter2
FROM Table1 A, Table2 B
WHERE A.Column_name = B.Column_name;
在写查询语句的时候,哀求语句的条件排列先后顺序要考虑语句实行的性能,要做到语句能很好的利用到现有的索引,一样平常原则上不许可在一条查询语句中有超过五张以上的表进行关联,由于当超过五张表关联时Oracle将不再做语句的优化处理;对语句的性能可以通过“实行操持”来跟踪,在PL/SQL Developer中的Explain Plan Window中可剖析ORACLE的实行操持。
以下是SELECT的语法,详细的利用方法请查阅干系资料
SELECT [DISTINCT | ALL] { | column1[, column2]...}
FROM {table_1 | (subquery)} [alias]
[, {table_2 | (subquery)} [alias]]...
[WHERE condition]
[CONNECT BY condition [START WITH condition]
[GROUP BY expn] [HAVING expn]
[{ UNION [ALL] | INTERSECT | MINUS } SELECT . . . ]
[ ORDER BY [expn ] [ ASC | DESC]
[ FOR UPDATE [OF [user.]table | view] column ]
[NOWAIT]
1.3 UPDATE语句的格式标准UPDATE Table SET Column_name1 = :Parameter1,
Column_name2 = :Parameter2
WHERE Column_name = :Pareameter;
以下是UPDATE的语法,详细的利用方法请查阅干系资料
UPDATE [user.]table[@db_link][alias]
SET { column1=express1[,column2=experss2]...|
(column1[,column2]...)=(subquery) }
[WHERE condition|current of cursor];
1.4 INSERT语句的格式标准INSERT INTO TableName(Column_name1,Column_name2)
VALUES(:Parameter1,:Parameter2)
或
INSERT INTO TableName(Column_name1,Column_name2)
SELECT Column_name1,Column_name2
FROM Table
WHERE Column_name = :Pareameter
不许可涌现 INSERT INTO TableName VALUES (:Parameter1,:Parameter2)的写法。
也不许可涌现 INSERT INTO TableName SELECT FROM Table 的写法。
1.5 DELETE语句的格式标准DELETE FROM TableName WHERE Column_name1 = :Parameter1
以下是DELETE的语法,详细的利用方法请查阅干系资料
DELETE [ FROM ] [user.]table [@db_link][Alias] [WHERE condition];
1.6 UNION,INTERSECT及MINUS有时须要从多个表中组合具有一种相似类型的信息。Union 可以完成将两个以上的表的相类似的查询结果合并在一起,并且相同的只取其一;如果union all 则表示返回所有行(不管是否重复)。Intersect返回在两个表中都有相同内容的信息。Minus 则返回只在一个表中涌现的信息
1. 语法:
select ...
union[all]
select ...
select ...
intersect
select ...
select ...
minus
select ...
以上语句进行连表操作,而表同表的字段顺序的类型相同但字段标题名可不同,利用ordey by时后面如果是字段名,哀求所有的表的字段标题名相同,否则用字段的顺序号
例如:
select id,name,year from user1
union
select no,name,to_number(null) year from user2
order by 1,name,year
union all ,union,Minus,INTERSECT 比较
个中union all 效率最好
Union 凑集并,不包含重复行
Union all 凑集并,可以包含重复行
Minus 凑集差,不包含重复行
INTERSECT 凑集交,不包含重复行
逻辑分表,大表分成多少小表
假设一个表的数据有2 千万行,我们可以针对这样给划分成5 个逻辑分表,每个分为500
万行的数据,对付历史数据我们可以分成这样的表来操作,例如一年12 个月每个月都可以
创建一个表.
orderr_01
...
order_12;
这样一个大表就可以有效地分成12 个表的操作,尤其可以按韶光或者按地域划分的都可以
这样操作。
可以创建视图连接多张表:
CREATE VIEW v_union_reginfo
AS
SELECT FROM reginfo
UNION ALL
SELECT FROM reginfo_temp
1.7 常用语句编写规范
例如: 条件语句
IF GA > 5 THEN
DBMS_OUTPUT.PUT_LINE('AAA');
ELSIF GA < 20 THEN
DBMS_OUTPUT.PUT_LINE('BBB');
ELSE
DBMS_OUTPUT.PUT_LINE('CCC');
END IF;
/语句开闭位置对应/
例如: 循环语句A:
FOR I IN 0..10 LOOP
DBMS_OUTPUT.PUT_LINE(I);
END LOOP;
/LOOP 和END LOOP 结束/
例如: 循环语句B:
DECLARE
GA NUMBER(3):=10;
BEGIN
WHILE GA <100 LOOP
DBMS_OUTPUT.PUT_LINE(GA);
GA := GA+1;
END LOOP;
END;
/LOOP 和END LOOP 结束/
1.8 游标规范
例如:
OPEN CUR_CRM_ORDER
LOOP
FETCH CUR_CRM_ORDER INTO
EXIT WHERE CUR_CRM_ORDER%NOTFOUND;
...
END LOOP;
CLOSE CUR_CRM_ORDER;
/程序中显示利用游标的规范/
带参数的游标写法
DECLARE
vregnick VARCHAR(20):='张三';
vregid INT;
cursor cu_a(var1 VARCHAR2) IS
SELECT regid INTO vregid FROM reginfo WHERE regnick=vregnick;
BEGIN
OPEN cu_a(vregnick) ;
Loop
FETCH cu_a INTO vregid;
EXIT WHEN cu_a%NOTFOUND;
dbms_output.put_line(vregid);
END LOOP;
CLOSE cu_a;
END;
Ref 游标,绑定变量的游标的下发
DECLARE
TYPE cur_type IS REF CURSOR;
cur cur_type;
vregnick VARCHAR(20):='张三';
vreginfo reginfo%ROWTYPE;
BEGIN
OPEN cur FOR 'select from reginfo where regnick=:a'
USING vregnick;
Loop
FETCH cur INTO vreginfo;
EXIT When cur%NOTFOUND;
dbms_output.put_line(vreginfo.regid);
END LOOP;
CLOSE cur;
END;
2 注释规范2.1 代码注释规范每个存储过程、触发器、包、函数的开头要有详细的解释,包括程序的名称、参数、功能、返回值以及编写韶光、编写职员等信息。每次修正在解释后面附上修正记录。
注释例子:
/
模块名称:
模块功能:
创建人:
创建韶光:
输入参数:
输出参数:
返回值:
修正历史:==============================
修君子:
修正韶光:
修正解释:
================================
/
2.2 注释位置哀求
1) 注释行的长度以在最大化窗口内可以看到全部内容为宜,如果一行不足显示须要换行,下一行注释语句与上一行注释语句应对齐。
2) 变量申明的注开释在变量申明语句的后面,并以-- 为注释语句
3) 注释行一律放在被注释语句的上一行。
4) 注释行中,注释命令与注释内容空一个空格,如:
V_BpMode VARCHAR2(10) ; -- 用户做事类型
BEGIN
-- 选取用户做事类型
BEGIN
SELECT BpMode INTO V_BpMode FROM ACC_BP WHERE User_ID = I_User_ID ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
WHEN OTHERS THEN
END ;
2.3 代码片断注释哀求1) 当处理流程比较繁芜,不随意马虎让其它人看懂时,该当加以注释。
2) 注释行放在 被注释的代码片断上一行,并与代码片断第一行对齐。
3 编码命名规范3.1 命名措辞命名该当利用英文单词,避免利用拼音,特殊不应该利用拼音简写。命名不许可利用中文或者分外字符。
英文单词利用工具本身意义相对或附近的单词。选择最大略或最通用的单词。不能利用绝不相关的单词来命名。
当一个单词不能表达工具含义时,用词组组合,如果组合太永劫,采取简写或缩写,缩写要基本能表达原单词的意义。
当涌现工具名重名时,是不同类型工具时,在工具名前后加类型前缀或后缀以示差异。
3.2 大小写名称一律大写,以方便不同数据库移植,以及避免程序调用问题。
3.3 单词分隔命名的各单词之间可以利用下划线“_”进行分隔。
3.4 保留字命名不许可利用SQL保留字。
3.5 命名长度表名、字段名、视图名长度应限定在20个字符内(含前缀)。
3.6 字段名称同一个字段名在一个数据库中只能代表一个意思。比如telephone在一个表中代表“电话号码”的意思,在其余一个表中就不能代表“手机号码”的意思。
不同的表用于相同内容的字段该当采取同样的名称,字段类型定义。
4 编码数据类型规范4.1 字符型固定长度的字串类型采取char,长度不固定的字串类型采取varchar。避免在长度不固定的情形下采取char类型。如果在数据迁移等涌现以上情形,则必须利用trim()函数截去字串后的空格。
4.2 数字型数字型字段只管即便采取number类型,要把稳精度。
4.3 日期和韶光4.3.1 系统韶光由数据库产生的系统韶光首选数据库的日期型,如DATE类型。
4.3.2 外部韶光由数据导入或外部运用程序产生的日期韶光类型采取varchar类型,数据格式采取:YYYYMMDDHH24MISS。
4.4 大字段如无特殊须要,避免利用大字段(blob,clob,long,text,image等)。
4.5 唯一键对付数字型唯一键值,尽可能用系列sequence产生。
5 SQL编码技巧性能常日是指软件的“韶光—空间”效率,而不仅是指软件的运行速率。人们总希望软件的运行速率快些,并且占用资源少些。
5.1 SELECT子句中避免利用Select 语句如果不是必要取出所有数据,不要用来代替,应给出字段列表,利用动态SQL列引用 '' 是一个方便的方法。但是,这是一个非常低效的方法。ORACLE在解析的过程中,会将'' 通过查询数据库系统的数据字典依次转换成所有对应的列名,这意味着将耗费更多的韶光和系统资源。
把稳别名的利用:
SELECT A.ORDER_ID,A.ORDER_CONTENT FROM CRM_ORDER A
/别名利用会加速查询速率/
并行查询 ,效率可以提高
第一种形式
SELECT /+ FULL(T) PARALLEL(T,2) / FROM CRM_ORDER T
/多cpu 利用如上语句可以加速查询速率适宜unix 做事器这样的配置/
第二种形式
SELECT /+ PARALLEL(T,2) / FROM CRM_ORDER T
5.2 避免嵌套的Select子句这个实际上是In子句的特例。
5.3 利用SELECT COUNT(主键)打算表的记录数和一样平常的不雅观点相反,count() 比count(1)稍快,当然如果可以通过索引检索,对索引列的计数仍旧是最快的。例如 COUNT(EMPNO)。如果没有主键SELECT COUNT(1) FROM stuinfo; 要快一些。
例如:
select count() from testtab
/得到表testtab的记录数/
select count(id) from testtab
/得到表testtab id字段非空记录数/
select count(distinct id) from testtab
/得到表testtab id字段值非相同记录数/
5.4 WHERE子句1) ORACLE采取自下而上的顺序解析WHERE子句,根据这个事理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末端。
2) 除非你不考虑实行效率问题,否则请不要在WHERE 子句中利用函数作为条件。例如 WHERE TO_NUMBER(TEL_NBR)=7654321 这种写法是效率非常低下的。
3) 避免利用HAVING子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤。 这个处理须要排序,总计等操作。如果能通过WHERE子句限定记录的数目,那就能减少这方面的开销。
4) 某些SELECT 语句中的WHERE子句不该用索引。
例如:
(1)‘!=' 将不该用索引。索引只能见告你什么存在于表中, 而不能见告你什么不存在于表中。
!= 运算符的利用.
不该用索引
SELECT FROM reginfo WHERE regid != 8
利用索引
SELECT FROM reginfo WHERE regid > 8 OR regid < 8
(2) ‘||'是字符连接函数. 就象其他函数那样, 停用了索引。
(3) ‘+'是数学函数。就象其他数学函数那样, 停用了索引。
(4)相同的索引列不能互比较较,这将会启用全表扫描。
5.5 用TRUNCATE替代DELETE当删除表中的记录时,在常日情形下, 回滚段(rollback segments ) 用来存放可以被规复的信息。 如果你没有COMMIT事务,ORACLE会将数据规复到删除之前的状态(准确地说是规复到实行删除命令之前的状况)。
而当利用TRUNCATE时, 回滚段不再存放任何可被规复的信息。当命令运行后,数据不能被规复。因此很少的资源被调用,实行韶光也会很短。
如果是删除全表,请利用TRUNCATE TABLE TabName 来替代 DELETE FROM TabName,能有效提高速率,并开释该表所占的存储空间,减少磁盘碎片。由于TRUNCATE TABLE是DDL措辞,在存储过程中不能直策应用,应加上EXECUTE IMMEDIATE,利用方法如下:EXECUTE IMMEDIATE ‘TRUNCATE TABLE TabName’;
利用前请把稳是否有权限问题。
5.6 只管即便多利用COMMIT只要有可能,在程序中只管即便多利用COMMIT,这样程序的性能得到提高,需求也会由于COMMIT所开释的资源而减少 。
COMMIT所开释的资源:
1) 回滚段上用于规复数据的信息。
2) 被程序语句得到的锁。
3) redo log buffer 中的空间。
4) ORACLE为管理上述3种资源中的内部花费。
5.7 关闭自动提交功能,提高系统性能在第一次建立与数据库的连接时,在缺省情形下,连接是在自动提交模式下的。为了得到更好的性能,可以通过调用带布尔值false参数的Connection类的setAutoCommit()方法关闭自动提交功能,如下所示:
conn.setAutoCommit(false);
值得把稳的是,一旦关闭了自动提交功能,我们就须要通过调用Connection类的commit()和rollback()方法来人工的办法对事务进行管理。
5.8 避免在索引列上利用IS NULL和IS NOT NULL任何SQL 语句,只要在where 子句中利用了is null 或is not null,那么Oracle 优化器就不许可利用索引了。
避免在索引中利用任何可以为空的列,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;
5.9 避免In子句利用In 或 not In子句时,特殊是当子句中有多个值时,且查询数据表数据较多时,速率会明显低落。可以采取连接查询或外连接查询来提高性能。
Char 比 varchar 查询时高效。在进行查询及建立索引时,char比varchar的效率要高,当然varchar在存储上比char要好。
/in 语句走得全表扫描/
SELECT FROM reginfo a WHERE a.regid
IN (SELECT b.regid FROM reginfo_temp b)
/精确的写法一:/
SELECT FROM reginfo a
WHERE EXISTS (SELECT 1 FROM reginfo_temp b WHERE a.regid=b.regid)
/精确写法二:/
SELECT a.regid,a.regnick FROM reginfo a
INNER JOIN reginfo_temp b ON a.regid=b.regid
/精确写法三早期sql 写法:/
SELECT a.regid,a.regnick FROM reginfo a, reginfo_temp b
WHERE a.regid=b.regid
5.10 用EXISTS替代IN在许多基于根本表的查询中,为了知足一个条件,每每须要对另一个表进行联接。在这种情形下,利用EXISTS(或NOT EXISTS)常日将提高查询的效率。
5.11 用NOT EXISTS替代NOT IN在子查询中,NOT IN子句将实行一个内部的排序和合并。无论在哪种情形下,NOT IN都是最低效的 (由于它对子查询中的表实行了一个全表遍历)。为了避免利用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS。
我们在查询时常常在where 子句利用一些逻辑表达式,如大于、小于、即是以及不即是等等,也可以利用and(与)、or(或)以及not(非)。NOT 可用来对任何逻辑运算符号取反。
下面是一个NOT 子句的例子:
... where not (status ='VALID')
如果要利用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT 运算符。NOT运算符包含在其余一个逻辑运算符中,这便是不即是(<>)运算符。换句话说,纵然不在查询where 子句中显式地加入NOT 词,NOT 仍在运算符中,见下例:
... where status <>'INVALID';
再看下面这个例子:
select from employee where salary<>3000;
对这个查询,可以改写为不该用NOT:
select from employee where salary<3000 or salary>3000;
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询许可Oracle 对salary 列利用索引,而第一种查询则不能利用索引。
有时候会将一列和一系列值比较较。最大略的办法便是在where 子句中利用子查询。在where 子句中可以利用两种格式的子查询。
第一种格式是利用IN 操作符:
... where column in(select from ... where ...);
第二种格式是利用EXIST 操作符:
... where exists (select 'X' from ...where ...);
我相信绝大多数人会利用第一种格式,由于它比较随意马虎编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle 中可以险些将所有的IN 操作符子查询改写为利用EXISTS 的子查询。
第二种格式中,子查询以‘select 'X'开始。利用EXISTS 子句不管子查询从表中抽取什么数据它只查看where 子句。这样优化器就不必遍历全体表而仅根据索引就可完成事情(这里假定在where 语句中利用的列存在索引)。相对付IN 子句来说,EXISTS 利用相连子查询,布局起来要比IN 子查询困难一些。
通过利用EXIST,Oracle 系统会首先检讨主查询,然后运行子查询直到它找到第一个匹配项,这就节省了韶光。Oracle 系统在实行IN 子查询时,首先实行子查询,并将得到的结果列表存放在在一个加了索引的临时表中。在实行子查询之前,系统先将主查询挂起,待子查询实行完毕,存放在临时表中往后再实行主查询。这也便是利用EXISTS 比利用IN 常日查询速率快的缘故原由。
同时应尽可能利用NOT EXISTS 来代替NOT IN,只管二者都利用了NOT(不能利用索引而降落速率),NOT EXISTS 要比NOT IN 查询效率更高。
5.12 用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, 那就须要返回记录最少的索引列写在最前面。
5.13 用UNION-ALL 更换UNION ( 如果有可能的话)当SQL语句须要UNION两个查询结果凑集时,这两个结果凑集会以UNION-ALL的办法被合并, 然后在输出终极结果提高行排序. 如果用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会因此得到提高. 须要把稳的是,UNION ALL 将重复输出两个结果凑集中相同记录. 因此各位还是要从业务需求剖析利用UNION ALL的可行性. UNION 将对结果凑集排序,这个操作会利用到SORT_AREA_SIZE这块内存. 对付这块内存的优化也是相称主要的。
5.14 用>=替代>高效: SELECT FROM EMP WHERE DEPTNO >=4
低效: SELECT FROM EMP WHERE DEPTNO >3
两者的差异在于, 前者DBMS将直接跳到第一个DEPT即是4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录。
5.15 Order by 语句ORDER BY 语句决定了Oracle 如何将返回的查询结果排序。Order by 语句对要排序的列没有什么特殊的限定,也可以将函数加入列中(联接或者附加等)。任何在Order by 语句的非索引项或者有打算表达式都将降落查询速率。
仔细检讨order by 语句以找出非索引项或者表达式,它们会降落性能。办理这个问题的办法便是重写order by 语句以利用索引,也可以为所利用的列建立其余一个索引,同时应绝对避免在order by 子句中利用表达式。
避免不必要的排序,不必要的数据排序大大的降落系统性能。
5.16 避免带通配符(%)的like 语句同样以上面的例子来看这种情形。目前的需求是这样的,哀求在职工表中查询名字中包含cliton 的人。可以采取如下的查询SQL 语句:
select from employee where last_name like '%cliton%';
这里由于通配符(%)在征采词首涌现,以是Oracle 系统不该用last_name 的索引。在很多情形下可能无法避免这种情形,但是一定要心中有底,通配符如此利用会降落查询速率。然而当通配符涌如今字符串其他位置时,优化器就能利用索引。不才面的查询中索引得到了利用:
select from employee where last_name like 'c%';
例如:
不该用索引情形:
SELECT FROM temp_stuinfo WHERE stu_add LIKE '%甘肃%';
利用索引情形
SELECT FROM temp_stuinfo WHERE stu_add LIKE '甘肃%';
可以利用oracle 函数instr 代替like 加快查询速率:
SELECT FROM temp_stuinfo WHERE instr(stu_add ,'肃')>0;
instr和like的性能比较:
实在从效率角度来看,谁能用到索引,谁的查询速率就会快。
like有时可以用到索引,例如:name like ‘李%’,而当下面的情形时索引会失落效:name like ‘%李’或者name like ‘%李%’。以是一样平常我们查找中文类似于‘%字符%’时,索引都会失落效。与其他数据库不同的是,oracle支持函数索引。例如在name字段上建个instr索引,查询速率就比较快了,这也是为什么instr会比like效率高的缘故原由。
注:instr(title,’手册’)>0 相称于like‘%手册%’
instr(title,’手册’)=0 相称于not like‘%手册%’
5.17 利用oracle全文检索对海量的文本数据进行搜索有很多时候,利用instr和like是很空想的, 特殊是搜索仅超过很小的表的时候。然而通过这些文本定位的方法将导致全表扫描,对资源来说花费比较昂贵,而且实现的搜索功能也非常有限,因此对海量的文本数据进行搜索时,建议利用oralce供应的全文检索功能。
设置全文检索:
步骤一:检讨和设置数据库角色
首先检讨数据库中是否有CTXSYS用户和CTXAPP脚色。如果没有这个用户和角色,意味着你的数据库创建时未安装intermedia功能(10G默认安装都有此用户和角色)。你必须修正数据库以安装这项功能。默认安装情形下,ctxsys用户是被锁定的,因此要先启用ctxsys的用户。
步骤二:赋权
在ctxsys用户下,付与测试用户oratext以下权限:
1 GRANT resource, CONNECT, ctxapp TO oratext;
2 GRANT EXECUTE ON ctxsys.ctx_cls TO oratext;
3 GRANT EXECUTE ON ctxsys.ctx_ddl TO oratext;
4 GRANT EXECUTE ON ctxsys.ctx_doc TO oratext;
5 GRANT EXECUTE ON ctxsys.ctx_output TO oratext;
6 GRANT EXECUTE ON ctxsys.ctx_query TO oratext;
7 GRANT EXECUTE ON ctxsys.ctx_report TO oratext;
8 GRANT EXECUTE ON ctxsys.ctx_thes TO oratext;
9 GRANT EXECUTE ON ctxsys.ctx_ulexer TO oratext;
步骤三:设置词法剖析器(lexer)
Oracle实现全文检索,其机制实在很大略。即通过Oracle专利的词法剖析器(lexer),将文章中所有的表意单元(Oracle 称为 term)找出来,记录在一组以dr$开头的表中,同时记下该term涌现的位置、次数、hash值等信息。检索时,Oracle从这组表中查找相应的term,并打算其涌现频率,根据某个算法来打算每个文档的得分(score),即所谓的‘匹配率’。而lexer则是该机制的核心,它决定了全文检索的效率。Oracle针对不同的措辞供应了不同的lexer,而我们常日能用到个中的三个:
basic_lexer:针对英语。它能根据空格和标点来将英语单词从句子等分离,还能自动将一些涌现频率过高已经失落去检索意义的单词作为‘垃圾’处理,如if,is等,具有较高的处理效率。但该lexer运用于汉语则有很多问题,由于它只认空格和标点,而汉语的一句话中常日不会有空格,因此,它会把整句话作为一个term,事实上失落去检索能力。以‘中国公民站起来了’这句话为例,basic_lexer剖析的结果只有一个term,便是‘中国公民站起来了’。此时若检索‘中国’,将检索不到内容。
chinese_vgram_lexer:专门的汉语剖析器,支持所有汉字字符集(ZHS16CGB231280 ZHS16GBK ZHT32EUC ZHT16BIG5 ZHT32TRIS ZHT16MSWIN950 ZHT16HKSCS UTF8 )。该剖析器按字为单元来剖析汉语句子。‘中国公民站起来了’这句话,会被它剖析成如下几个term:‘中’,‘中国’,‘国人’,‘公民’,‘民站’,‘站起’,起来’,‘来了’,‘了’。可以看出,这种剖析方法,实现算法很大略,并且能实现‘一扫而空’,但效率则是差强人意。
chinese_lexer:这是一个新的汉语剖析器,只支持utf8字符集。上面已经看到,chinese vgram lexer这个剖析器由于不认识常用的汉语词汇,因此剖析的单元非常机器,像上面的‘民站’,‘站起’在汉语中根本不会单独涌现,因此这种term是没故意义的,反而影响效率。chinese_lexer的最大改进便是该剖析器能认识大部分常用汉语词汇,因此能更有效率地剖析句子,像以上两个屈曲的单元将不会再涌现,极大提高了效率。但是它只支持utf8,如果你的数据库是zhs16gbk字符集,则只能利用笨笨的那个Chinese vgram lexer。如果不做任何设置,Oracle缺省利用basic_lexer这个剖析器。
要指定利用哪一个lexer,可以这样操作:
第一.建立一个preference:
1EXEC ctx_ddl.create_preference ('my_lexer', 'chinese_vgram_lexer');
第二.在建立全文索引时,指明所用的lexer:
1CREATE INDEX myindex ON mytable(mycolumn) indextype IS ctxsys.context parameters('lexer my_lexer');
这样建立的全文检索索引,就会利用chinese_vgram_lexer作为剖析器。
全文检索举例:
测试用户为oratext,建立此用户和对应表空间的内容就不写了:
步骤一:授权,ctxsys上岸并对oratext用户授权:
GRANT resource, CONNECT, ctxapp TO oratext;
GRANT EXECUTE ON ctxsys.ctx_cls TO oratext;
GRANT EXECUTE ON ctxsys.ctx_ddl TO oratext;
GRANT EXECUTE ON ctxsys.ctx_doc TO oratext;
GRANT EXECUTE ON ctxsys.ctx_output TO oratext;
GRANT EXECUTE ON ctxsys.ctx_query TO oratext;
GRANT EXECUTE ON ctxsys.ctx_report TO oratext;
GRANT EXECUTE ON ctxsys.ctx_thes TO oratext;
GRANT EXECUTE ON ctxsys.ctx_ulexer TO oratext;
步骤二:设置词法剖析器,利用chinese_vgram_lexer作为剖析器:
BEGIN
--设置词法剖析器
ctx_ddl.create_preference ('oratext_lexer', 'chinese_vgram_lexer');
END;
可以通过下面的语句查看系统默认及设置的oracle text参数:
SELECT pre_name, pre_object FROM ctx_preferences
可以看到我刚刚设置的语法剖析器参数oratext_lexer,(默认的有一个MY_LEXER的语法剖析器参数)。
步骤三:建立测试表,插入测试数据:
CREATE TABLE textdemo(
id NUMBER NOT NULL PRIMARY KEY,
book_author varchar2(20),--作者
publish_time DATE,--发布日期
title varchar2(400),--标题
book_abstract varchar2(2000),--择要
path varchar2(200)--路径
);
commit;
INSERT INTO textdemo VALUES(1,'宫琦峻',to_date('2008-10-07','yyyy-mm-dd'),' 移动城堡','故事发生在19世纪末的欧洲,善良可爱的苏菲被毒辣的女巫施下魔咒,从18岁的女孩变成90岁的婆婆,孤单无助的她无意中走入镇外的移动城堡,听说它的主人哈尔以吸取女孩的灵魂为乐,但是事情并没有人们传说的那么恐怖,脾气古怪的哈尔居然收留了苏菲,两个人在四脚的移动城堡中开始了奇妙的共同生活,一段交织了爱与痛、乐与悲的爱情故事在战火中悄悄展开','E:\textsearch\moveingcastle.doc');
INSERT INTO textdemo VALUES(2,'莫贝克曼贝托夫',to_date('2008-10-07','yyyy-mm-dd'),' 子弹转弯','这部由俄罗斯导演提莫贝克曼贝托夫执导的影片自6 月末在北美上映以来,已经在环球取得了超过3亿美元的票房收入。在亚洲上映后也先后拿下日本、韩国等地的票房冠军宝座。虽然不少网友在此之前也相继通过各种渠道打仗到本片,但相信影片凭着在大银幕上呈现出的超酷的视听效果,依然能够吸引大量影迷前往影院捧场。','E:\textsearch\catch.pdf');
INSERT INTO textdemo VALUES(3,'袁泉',to_date('2008-10-07','yyyy-mm-dd'),'主演吴彦祖和袁泉现身','电影《如梦》在上海同乐坊拍摄,主演吴彦祖和袁泉现身。由于是深夜拍摄,以是周围并没有过多的fans把稳到,给了剧组一个很清净的拍摄环境,站在街头的袁泉低着头,在寒冷的夜里看上去还真有些像女鬼,令人不寒而栗。','E:\textsearch\dream.txt');
commit;
步骤四:在book_abstract字段建立索引利用刚刚设置的ORATEXT_LEXER :chinese_vgram_lexer作为剖析器。
CREATE INDEX demo_abstract ON textdemo(book_abstract) indextype IS ctxsys.context parameters('lexer ORATEXT_LEXER');
commit;
之后如上所述多出很多dr$开头的表和索引,系统会创建四个干系的表:
DR$DEMO_ABSTRACT$I(分词后的TOKEN表)\DR$DEMO_ABSTRACT$K\DR$DEMO_ABSTRACT$N \DR$DEMO_ABSTRACT$R
下面的语句可以查看索引创建过程中是否发生了缺点:
SELECT FROM ctx_USER_index_errors
附:对付建立索引的类型(例如ctxsys.context),包括四种:context,ctxcat,ctxrule,ctxxpath。
CONTEXT用于对含有大量连续文本数据进行检索。支持word、html、xml、text等很多数据格式。支持范围(range)分区,支持并行创建索引(Parallel indexing)的索引类型。
支持类型:VARCHAR2, CLOB, BLOB, CHAR, BFILE, XMLType, and URIType.DML。操作后,须要CTX_DDL.SYNC_INDEX手工同步索引如果有查询包含多个词语,直接用空格隔开(如 oracle itpub)。
查询标识符CONTAINS
CTXCAT适用于稠浊查询语句(如查询条件包括产品id,价格,描述等)。适宜于查询较小的具有一定构造的文本段。具有事务性。DML 操作后,索引会自动进行同步。
操作符:and,or,>,;<, =,between,in
查询标识符CATSEARCH
CTXRULE查询标识符MATCHES。
CTXXPATH(这两个索引没有去更多搜索干系内容)
一样平常来说我们建立CONTEXT类型的索引(CONTAINS来查询)。
步骤五:查询测试
--查询或
SELECT score(20),t. FROM textdemo t WHERE contains(book_abstract,'移动城堡 or 俄罗斯',20)>0;
SELECT score(20),t. FROM textdemo t WHERE contains(book_abstract,'移动城堡 or 欧洲',20)>0;
--基本查询
SELECT score(20),t. FROM textdemo t WHERE contains(book_abstract,'移动城堡',20)>0;
--查询包含多个词语and测试通过
SELECT score(20),t. FROM textdemo t WHERE contains(book_abstract,'移动城堡 and 欧洲',20)>0;
测试通过。
5.18 利用CREATE TABLE AS 替代INSERT INTO…select如果可能,请利用
CREATE TABLE TabName AS SELECT FROM ……
来替代
INSERT INTO TabName SELECT FROM …… ,
特殊是在记录数比较多的情形下,前者的速率上会有非常明显的上风。
5.19 用索引提高效率索引是表的一个观点部分,用来提高检索数据的效率,ORACLE利用了一个繁芜的自平衡B-tree构造。常日,通过索引查询数据比全表扫描要快。当ORACLE找出实行查询和Update语句的最佳路径时, ORACLE优化器将利用索引。同样在联接多个表时利用索引也可以提高效率。另一个利用索引的好处是,它供应了主键(primary key)的唯一性验证。那些LONG或LONG RAW数据类型, 你可以索引险些所有的列。常日, 在大型表中利用索引特殊有效。当然,你也会创造,在扫描小表时,利用索引同样能提高效率。虽然利用索引能得到查询效率的提高,但是我们也必须把稳到它的代价。索引须要空间来存储,也须要定期掩护, 每当有记录在表中增减或索引列被修正时, 索引本身也会被修正。这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O 。由于索引须要额外的存储空间和处理,那些不必要的索引反而会使查询反应韶光变慢。
/定期的重构索引是有必要的 /
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
必要的时候可以逼迫利用索引
SELECT /+ INDEX(CRM_ORDER INDEX_A) / FROM CRM_ORDER A
/逼迫利用索引可以加快查询速率/
索引对SQL性能的提高:
/不该用索引的情形,如果在字段regtime 上创建了索引:/
SELECT FROM reginfo WHERE to_char(regtime,'yyyy-mm-dd') ='2013-01-01';
这时候上面语句就没有走索引.
换成如下语句:
SELECT FROM reginfo WHERE regtime = to_date('2013-01-01','yyyy-mm-dd');
效果就好些.
或者创建函数索引.
CREATE INDEX index_abc ON reginfo(to_char(regtime,'yyyy-mm-dd'));
组合索引(索引字段最好不超过三个)举例:
如果我们在查询中利用两列作为条件,就可以创建组合索引
CREATE INDEX index_com ON reginfo(regnick,regtime)
例子:
SELECT FROM reginfo WHERE regnick='张三' AND regtime=to_date('2013-1-1','yyyy-mm-dd');
/利用了索引index_com/
SELECT FROM reginfo WHERE regnick='张三' 也利用了索引index_com
如果我们在regnick 和regtime 上面分别创建了单列索引,通过联合查询后,效率也没有组合索引好些。
如果下查询
SELECT FROM reginfo WHERE regtime=to_date('2013-1-1','yyyy-mm-dd')
这时利用了组合索引的第二个字段,但是oracle9i 往后就利用了跳跃式索引,如果加上优化便是用了跳跃式索引:
例子:
SELECT /+index(reginfo index_com)/ FROM reginfo WHERE
regtime=to_date('2013-1-1','yyyy-mm-dd');
跳跃索引比全表扫描也快,但是要慢于单列索引,以是有必要创建单列索引在此列上。
nvl 相同索引列不能互比较较
/不该用索引的情形:/
SELECT FROM reginfo WHERE regnick = nvl(regnick,'张三');
/利用索引的情形/
SELECT FROM reginfo WHERE regnick LIKE nvl(regnick,'%');
/不要在索引列上利用运算/
SELECT FROM temp_stuinfo WHERE substr(stu_name,1,1)='张';
5.20 选择最有效率的表名顺序(只在基于规则的优化器中有效)
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在末了的表(根本表 driving table)将被最先处理。在FROM子句中包含多个表的情形下,你必须选择记录条数最少的表作为根本表。当ORACLE处理多个表时, 会利用排序及合并的办法连接它们。首先,扫描第一个表(FROM子句中末了的那个表)并对记录进行排序,然后扫描第二个表(FROM子句中末了第二个表),末了将所有从第二个表中检索出的记录与第一个表中得当记录进行合并。
如果有3个以上的表连接查询, 那就须要选择交叉表(intersection table)作为根本表, 交叉表是指那个被其他表所引用的表。
5.21 共享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) 字符级的比较: 当前被实行的语句和共享池中的语句必须完备相同。
b) 两个语句所指的工具必须完备相同。
c) 两个SQL语句中必须利用相同的名字的绑定变量(bind variables)。
6 健壮性健壮性是指在非常情形下,软件能够正常运行的能力。精确性与健壮性的差异是:前者描述软件在需求范围之内的行为,后者描述软件在需求范围之外的行为。想不到非常情形,把非常错当正常而不作处理,这些都会降落健壮性。提高软件的健壮性也是开拓者的责任。
健壮性有两层含义:一是容错能力,二是规复能力。
容错是指发生非常情形时系统不出错误的能力。高风险系统如航空航天、武器、金融等领域的系统,容错性设计非常主要。
容错是非常健壮的意思。而规复则是指软件发生缺点后(不论去世活)重新运行时,能否规复到没有发生缺点前的状态的能力。
从语义上理解,规复不及容错那么健壮。
6.1 在创建存储过程语句中供应必要的参数创建存储过程语句可以包含很多参数,虽然从语法角度讲它们不是必须的,但是在创建存储过程时供应这些参数可以提高实行效率。
6.2 对输入参数进行必要的的检讨和预处理无论利用哪种编程措辞,对输入参数的判断都是必须的。精确的参数验证是担保程序良好运行的条件。
精确的验证和预处理操作包括:
如果输入参数缺点,存储过程应返回一个明确的值见告客户运用,然后客户运用可以根据返回的值进行处理,或者向存储过程提交新的参数,或者去调用其他的程序。
根据业务逻辑,对输入参数作一定的预处理,如大小写的转换,NULL与空字符串或0的转换等。
6.3 非常处理在存储过程实行的过程中,常常由于数据或者其他问题产生非常(condition)。根据业务逻辑,存储过程该当对非常进行相应处理或直接返回给调用者。此处暂且将condition译为非常以方便理解。实际上有些非常(condition)并非是由于缺点引起的。
6.4 PL/SQL 非常处理规范对付存储过程、函数等程序块都要有非常处理部分,以提高程序的自检能力。
例如:
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
6.5 在 PL/SQL 中利用 sqlcode,sqlerrm当存储过程实行出错抛出EXCEPTION时,可通过 sqlcode 和 sqlerrm取得当前的ORACLE缺点代码和缺点信息,以下是利用范例:
DECLARE
V_SQLCODE number(6);
V_ERRMSG varchar2(512);
BEGIN
UPDATE dept SET username = (SELECT username FROM work_group)
WHERE rownum=1;
EXCEPTION
WHEN OTHERS THEN
V_SQLCODE := sqlcode;
V_ERRMSG := sqlerrm;
Dmbs_output.put_line (‘程序出错,缺点代码:’|| V_SQLCODE||’缺点信息:’|| V_ERRMSG);
END;
6.6 后台验证非常信息规范利用数据库过程、函数进行后台数据验证时,创造非常情形,须要记录非常,并返回到用户界面。
非常信息描述哀求简洁、准确、完全,揭示非常本色,准确定位非常涌现的位置。
非常分为警告和缺点两类。
由于每个实际项目,业务不同,非常信息也变革很大。每个项目开始时根据需求,统一进行定义。
6.7 Insert语句健壮性利用Insert语句一定要给出要插入值的字段列表,这样纵然变动了表构造加了字段也不会影响现有系统的运行。
6.8 外键值可用null的问题外键列如没有明确解释not null,可插入null记录(而null是在外部表的记录中没有的),如无可插null记录的想法,要对外键字段加not null约束。
6.9 序列 sequence 跳号的问题sequence 因回滚,系统崩溃(利用cache 内的值将认为已用),多表引用都将使其跳号,以是不能用于连续序号 。
7 安全性和完全性约束无论在利用Select,还是利用毁坏力极大的Update和Delete语句时,一定要检讨Where条件判断的完全性,不要在运行时涌现数据的重大丢失。
如果不愿定,最好先用Select语句带上相同条件来验证一下结果集,来考验条件是否精确。
有依赖关系的表,例如主外键关系表,在删除父表时必须级联删除其子表相应数据,或则按照某种业务规则转移该数据。9I中表中字段缩小及变类型,字段为空或表空,varchar和char长度不变可任意改,字段名和表名字段可用 ALTER TABLE table SET UNUSED (column) 设定为不可用,把稳无命令再设为可用。