A. sql优化器基于规则优化器和基于成本优化器的区别
Oracle有两种优化器:RBO和CBO。 RBO的最大的问题在于它是靠硬编码在ORACLE数据库代码中的一系列规定的规则来决定目标SQL的执行计划的,而并没有考虑目标SQL中所涉及的对象的时间数据量,实际数据分布情况,这样一旦规定规则并不适用于该SQL中所涉及的实际对象时,RBO根据规定规则产生的执行计划就很可能不是当前情况下的最优执行计划了。
下面我们来看如下的例子:
select * from EMP_TEMP where manager_id=100;
假设在EMP_TEMP的manager_id上事先有名为IDX_MGR_TEMP的单键值B数索引,如果我们用的是RBO,则不管EMP_TEMP的数据量多大,也不管MANAGER_ID的数据分布如何,ORACLE执行的时候始终会选择做对IDX_MGR_TEMP的范围索引扫描,并回表取得EMP_TEMP中的记录。ORACLE是不会选择全表扫描EMP_TEMP表的,因为对于RBO而言,全表扫描的等级值要高于索引范围扫描值的等级值。
RBO的这种选择在表EMP_TEMP的数据量不大,而且满足manager_id=10的条件的记录少的情况下是影响不大的,如果表EMP_TEMP的数据量非常大,例如1000万条记录,
而且这1000万条记录的MANAGER_ID的值都是100,在这种极端的情况下,如果是RBO,显然它任然用IDX_MGR_TEMP索引范围扫描,这个时候性能肯定是很差的。因为相当于以单块顺序扫描所有的1000万行索引,然后再回表1000万次。显然没有使用多块以全表扫描方式直接扫描表EMP_TEMP的执行效率高。所以为了解决RBO的这个先天的缺陷,从ORACLE 7开始,ORACLE就引入了CBO。CBO在选择目标SQL的执行计划时,是用执行成本作为判断原则的。CBO会从目标SQL诸多可能的执行路径中选择一条成本值最小的执行路径作为其执行计划,各条执行路径的成本是根据目标SQL语句所涉及的表,索引,列等相关对象的统计信息计算出来的。这些信息存储在ORACLE的数据库的数据字典里,且从多个维度描述了ORACLE数据库里相关对象的实际数据量,实际数据分布等详细信息。
NOTE:ORACLE在对一条执行路径计算成本时,并不一定从头到尾完整计算完,只是要ORACLE在计算过程中发现算出来的部分成本值已经大于之前保存下来的到目前为止的最小成本值,就会马上终止对当前执行路径成本值的计算,并转而开始计算下一条新的执行路径的成本。这个过程会一直持续下去,直到目标SQL的给各个可能的执行路径全部计算完毕或已经达到预先定义好的待计算的执行路径数量的阀值。
RBO是根据硬编码在ORACLE数据库中来决定目标SQL的执行计划的,并没有考虑目标SQL所所涉及的对象的实际数据量,实际分布情况等。而CBO则恰恰相反,它会根据目标SQL的相关的对象的实际数据量,实际数据分布情况的统计信息来决定其执行计划,即意味着CBO是随着目标SQL中所涉及的对象的统计信息的变化而变化的。这就意味着只有统计信息相对准确,则用CBO来解析目标SQL会比同等条件下的RBO来解析得到正确执行计划的概率要高。
当然CBO并不是完美的,它的缺陷主要表现在:
1,CBO会默认目标SQL语句的WHERE条件中出现的各个列之间是独立的,没有关系的。
2,CBO会假设所有的目标SQL都是单独执行的,并且互不干扰。
3,CBO对直方图统计信息有诸多限制。
4,CBO在解析多个表关联的目标SQL时,可能会漏掉正确的执行计划。
B. SQL 语句优化问题
事实上,这样的担心是不必要的。SQL
SERVER中有一个“查询分析优化器”,它可以计算出WHERE子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间,也就是说,它能实现自动优化。
虽然查询优化器可以根据WHERE子句自动的进行查询优化,但仍然有必要了解一下“查询优化器”的工作原理,如非这样,有时查询优化器就会不按照您的本意进行快速查询。
在查询分析阶段,查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数(SARG),那么就称之为可优化的,并且可以利用索引快速获得所需数据。
SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接。形式如下:
列名
操作符
<常数
或
变量>或<常数
或
变量>
操作符列名
列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:
Name=’张三’价格>5000
5000<价格
Name=’张三’
and
价格>5000
如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是SQL
SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。所以一个索引对于不满足SARG形式的表达式来说是无用的。
常见的SARG判别经验:
Like语句是否属于SARG取决于所使用的通配符的类型
如:name
like
‘张%’,这就属于SARG
而:name
like
‘%张’,就不属于SARG。
原因是通配符%在字符串的开通使得索引无法使用。
or
会引起全表扫描。
Name
=
’张三’
AND
价格>5000,符合SARG,
Name
=
’张三’
OR
价格>5000,不符合SARG。
原因是使用or会引起全表扫描。
非操作符、函数引起的不满足SARG形式的语句。
不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT
EXISTS、NOT
IN、NOT
LIKE等,另外还有函数。下面就是几个不满足SARG形式的例子:
ABS(价格)<5000
Name
like
‘%三’
有些表达式,如:WHERE
价格*2>5000
SQL
SERVER也会认为是SARG,SQL
SERVER会将此式转化为:价格>5000/2
但不推荐这样使用,因为有时SQL
SERVER不能保证这种转化与原始表达式是完全等价的。
C. 关于SQL数据库优化
具体要注意的:
1.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。
3.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
4.in 和 not in 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据。如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
5.尽量避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎无法利用索引。
见如下例子:
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’
SELECT * FROM T1 WHERE NAME LIKE ‘L%’
即使NAME字段建有索引,前两个查询依然无法利用索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。而第三个查询能够使用索引来加快操作。
6.必要时强制查询优化器使用某个索引,如在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
select id from t where num=@num
可以改为强制查询使用索引:
select id from t with(index(索引名)) where num=@num
7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
SELECT * FROM T1 WHERE F1/2=100
应改为:
SELECT * FROM T1 WHERE F1=100*2
SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’
应改为:
SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’
SELECT member_number, first_name, last_name FROM members
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21
应改为:
SELECT member_number, first_name, last_name FROM members
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())
即:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)='abc'--name以abc开头的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
应改为:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
11.很多时候用 exists是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select top 1 from b where num=a.num)
SELECT SUM(T1.C1)FROM T1 WHERE(
(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)
SELECT SUM(T1.C1) FROM T1WHERE EXISTS(
SELECT * FROM T2 WHERE T2.C2=T1.C2)
两者产生相同的结果,但是后者的效率显然要高于前者。因为后者不会产生大量锁定的表扫描或是索引扫描。
如果你想校验表里是否存在某条纪录,不要用count(*)那样效率很低,而且浪费服务器资源。可以用EXISTS代替。如:
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')
可以写成:
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')
经常需要写一个T_SQL语句比较一个父结果集和子结果集,从而找到是否存在在父结果集中有而在子结果集中没有的记录,如:
SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表示tbl用别名a代替
WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)
SELECT a.hdr_key FROM hdr_tbl a
LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL
SELECT hdr_key FROM hdr_tbl
WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl)
三种写法都可以得到同样正确的结果,但是效率依次降低。
12.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
13.避免频繁创建和删除临时表,以减少系统表资源的消耗。
14.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
15.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
16.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
17.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
18.尽量避免大事务操作,提高系统并发能力。
19.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
20. 避免使用不兼容的数据类型。例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。例如:
SELECT name FROM employee WHERE salary > 60000
在这条语句中,如salary字段是money型的,则优化器很难对其进行优化,因为60000是个整型数。我们应当在编程时将整型转化成为钱币型,而不要等到运行时转化。
21.充分利用连接条件,在某种情况下,两个表之间可能不只一个的连接条件,这时在 WHERE 子句中将连接条件完整的写上,有可能大大提高查询速度。
例:
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO
第二句将比第一句执行快得多。
22、使用视图加速查询
把表的一个子集进行排序并创建视图,有时能加速查询。它有助于避免多重排序 操作,而且在其他方面还能简化优化器的工作。例如:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.postcode>“98000”
ORDER BY cust.name
如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个视图中,并按客户的名字进行排序:
CREATE VIEW DBO.V_CUST_RCVLBES
AS
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY cust.name
然后以下面的方式在视图中查询:
SELECT * FROM V_CUST_RCVLBES
WHERE postcode>“98000”
视图中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。
23、能用DISTINCT的就不用GROUP BY
SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID
可改为:
SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10
24.能用UNION ALL就不要用UNION
UNION ALL不执行SELECT DISTINCT函数,这样就会减少很多不必要的资源
35.尽量不要用SELECT INTO语句。
SELECT INOT 语句会导致表锁定,阻止其他用户访问该表。
上面我们提到的是一些基本的提高查询速度的注意事项,但是在更多的情况下,往往需要反复试验比较不同的语句以得到最佳方案。最好的方法当然是测试,看实现相同功能的SQL语句哪个执行时间最少,但是数据库中如果数据量很少,是比较不出来的,这时可以用查看执行计划,即:把实现相同功能的多条SQL语句考到查询分析器,按CTRL+L看查所利用的索引,表扫描次数(这两个对性能影响最大),总体上看询成本百分比即可。
今天在itput上看了一篇文章,是讨论一个语句的优化:
原贴地址: http://www.itpub.net/viewthread.php?tid=1015964&extra=&page=1
一,发现问题 优化的语句:
请问以下语句如何优化:
CREATE TABLE aa_001
( ip VARCHAR2(28),
name VARCHAR2(10),
password VARCHAR2(30) )
select * from aa_001 where ip in (1,2,3) order by name desc;
--目前表中记录有一千多万条左右,而且in中的值个数是不确定的。
以上就是优化的需要优化的语句和情况。
不少人在后面跟帖:有的说没办法优化,有的说将IN该为EXISTS,有的说在ip上建立索引复合索引(ip,name)等等。
二,提出问题 那这样的情况,能优化吗,如何优化?今天就来讨论这个问题。
三,分析问题 1,数据量1千万多条。
2,in中的值个数是不确定
3.1 分析数据分布 这里作者没有提到ip列的数据的分布情况,目前ip列的数据分布可能有以下几种:
1,ip列(数据唯一,或者数据重复的概率很小)
2,ip列 (数据不均匀,可能有些数据重复多,有些重复少)
3,ip列 (数据分布比较均匀,数据大量重复,主要就是一些同样的数据(可能只有上万级别不同的ip数据等)
解决问题:
1,对于第一种数据分布情况,只要在ip列建立一个索引即可。这时不管表有多少行, in个数是不确定的情况下,都很快。
2,对应第二中数据分布情况,在ip列建立索引,效果不好。因为数据分布不均匀,可能有些快,有些慢
3,对应第三种数据分布情况,在ip列建立索引,速度肯定慢。
注意:这里的 order by name desc 是在取出数据后再排序的。而不是取数据前排序
对于2,3两个情况,因为都是可能需要取出大量的数据,优化器就采用表扫描(table scan),而不是索引查找(index seek) ,速度很慢,因为这时表扫描效率要优于索引查找,特别是高并发情况下,效率很低。
那对应2,3中情况,如何处理。是将in改成exists。其实在sql server 2005和oracle里的优化器在in后面数据少时,效率是一样的。这时采用一般的索引效率很低。这时如果在ip列上建立聚集索引,效率会比较高。我们在SQL server 2005中做个测试。
表:[dbo].[[zping.com]]]中有约200万条数据。包含列Userid, id, Ruleid等列。按照上面的情况查询一下类似语句:
select * from [dbo].[[zping.com]]] where
userid in ('',''
,'') order by Ruleid desc
我们先看userid的数据分布情况,执行下面语句:
select userid,count(*) from [dbo].[[zping.com]]] group by userid order by 2
这时我们看看数据分布:总共有379条数据,数据两从1到15万都有,数据分布倾斜严重。下图是其中一部分。
这时如果在ip上建立非聚集索引,效率很低,而且就是强行索引扫描,效率也很低,会发现IO次数比表扫描还高。这时只能在ip上建立聚集索引。这时看看结果。
这时发现,搜索采用了(clustered index seek)聚集搜索扫描。
在看看查询返回的结果:
(156603 行受影响)
表 '[zping.com]'。扫描计数 8,逻辑读取 5877 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
返回15万行,才不到6千次IO。效率较高,因为这15万行要排序,查询成本里排序占了51%。当然可以建立(userid,Ruleid)复合聚集索引,提高性能,但这样做DML维护成本较高。建议不采用。
从上面的测试例子可以看出, 优化的解决办法:
数据分布为1:建立ip索引即可
数据分布为2,3:在ip列建立聚集索引。
D. 怎样进行sql数据库的优化
1、数据库空间是个概述,在sqlserver里,使用语句 exec sp_spaceused 'TableName' 这个语句来查。
E. 数据库系统优化的人工智能自动SQL优化
人工智能自动SQL优化出现在90年代末。目前在商用数据库领域,LECCO Technology Limited(灵高科研有限公司)拥有该技术,并提供使用该技术的自动优化产品LECCO SQL Expert,它支持Oracle、Sybase、MS SQL Server和IBM DB2数据库平台。该产品针对数据库应用的开发和维护阶段提供的模块有:SQL语法优化器、PL/SQL集成化开发调试环境(IDE)、扫描器、数据库监视器等。其核心模块SQL 语法优化器的工作原理为:①输入一条源SQL语句;②“人工智能反馈式搜索引擎”对输入的SQL语句,结合检测到的数据库结构和索引进行重写,产生N条等效的SQL语句输出;③产生的N条等效SQL语句再送入“人工智能反馈式搜索引擎”进行重写,直至无法产生新的输出或搜索限额满;④对输出的SQL语句进行过滤,选出具有不同执行计划的SQL语句;⑤对得到的SQL语句进行批量测试,找出性能最好的SQL语句。
F. SQL查询优化、SQL执行计划及优化器之间什么关系
一,SQL查询优化:指,使用的语句是不是冗余的,就是有没有无用的。
你可用用explain 你的语句来比较分板一番。比如:select * from wc where 1;与select * from wc二者的执行时间不一样的;
二,SQL执行计划就是用于描述SQL引擎在执行一个sql语句时的所有步骤,通过执行计划,我们可以知道哪个表是驱动表,如何访问一个表:是通过索引访问还是通过表扫描,如何进行连接:使用嵌套连接,合并连接还是哈希连接,连接的顺序等等;
在我们处理执行计划的过程中,一般有三个步骤:
获取执行计划
理解执行计划
判断其效率
2.获取执行计划的方式
Oracle提供了以下几种方法获得sql语句的执行计划:
2.1 explain plan
这种方法用于给出当前的sql文本的评估的执行计划,oracle并不会执行相应的sql语句,而且如果sql语句有绑定参数,那么得到的执行计划并不一定就是确切的执行计划,还要根据条件中的列是否有直方图和cursor_sharing参数的配置值来判断。
a. 在sqlplus 中执行explain plan
SQL>Explain plan set sql_id=’mysql’ for select * from temp;
b. 使用dbms_xplan显示执行计划
select * from table(dbms_xplan.display());
或者:select * from table(dbms_xplan.display(statement_id => ‘mysql’));
三,优化器;是SQL执行效率的重构工具。
可以帮助将低效率的SQL优化成为高效率的。
一般主要针对查询语句。
将更多的判断条件已到叶子节点上去操作。
G. 如何优化sql语句
一、问题的提出
在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一。系统优化中一个很重要的方面就是SQL语句的优化。对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的SQL语句,提高系统的可用性。
在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句。
二、SQL语句编写注意问题
下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。
1. IS NULL 与 IS NOT NULL
不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。
任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。
2. 联接列
对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。我们一起来看一个例子,假定有一个职工表(employee),对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。
下面是一个采用联接查询的SQL语句,
select * from employss where first_name||''||last_name ='Beill Cliton';
上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。
当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。
*** where first_name ='Beill' and last_name ='Cliton';
. 带通配符(%)的like语句
同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句:
select * from employee where last_name like '%cliton%';
这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用:
select * from employee where last_name like 'c%';
4. Order by语句
ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。
仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。
5. NOT
我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:
... where not (status ='VALID')
如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:
... where status <>'INVALID';
对这个查询,可以改写为不使用NOT:
select * from employee where salary<3000 or salary>3000;
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。