http://lzfhope.blog.163.com/blog/static/6363992200811296039755/?suggestedreading&wumii
环境:ORACLE 10G
这里着重要研究的是一些很常见的,但是有和性能有密切关系的写法。
不讨论函数,索引,分区等等因素,主要是SQL引擎的执行计划,具体一点就是:连接,条件,视图(主要是内建视图)。
限于本人对于SQL引擎的了解,这里逐一列举几个例子。
一) 关于 where 条件后面的常量表达式,例如1=1
事实上,这是为了方便编写动态sql而写的 ,有的人也到处都这么写,仅仅是因为一个习惯,但是不建议到处写。会不会影响性能呢? 结论是 基本上不会影响,为什么呢? 因为10g的SQL引擎在解析前已经把这个条件过滤掉了。
推而广之,其实大部分最终可以变为常量的表达式,都会在解析的时候被计算为常量:一个字符串,一个数值,或者一个布尔变量。
如果存在这样的一个where 子句
(1=1) and xxx ,那么会解析为 xxx.
(1>1) and xxx ,会解析为 false ,并且不执行查询
(1=1) or xxx , 解析为 xxx
(1>1) or xxx , 解析为 false ,并且不执行查询.
cola>100/2 ,会解析为cola>50
所以,针对很久以前的sql解析的法则,现在已经不通了,大家写的时候也不要再去关注,当然cola>100/2还是写成cola>50 比较好,无论如何解析也是需要花费时间的。
二)关联条件还是过滤条件的选择
例如有两个表格,
员工表 a(id,dept,name) , 工资表b(id,mon,salary)
查询特定月份每个部门累计工资,可以如下编写
select a.dept,sum(b.salary) from
a join b on b.id=a.id where b.mon = 200812 group by a.dept
也可以如此写
select a.dept,sum(b.salary) from
a join b on b.id=a.id and b.mon = 200812 group by a.dept
它们的分析计划是一样的,这是因为对于oracle 10g的SQL引擎而言,可以单单作用于一个表格上的条件,是需要先在表格内部处理,然后才会处理其它步骤。
上例子是针对join(简单连接或者内连接),我的结论是:选择关联条件还是过滤条件对于内连接是没有差别的。
如果是外部连接(outer)或者其它连接(anti 差,semi 交)则另当别论!
如果结合上索引情况会更复杂,不过这里暂时不说索引的事情。
无论如何,谨记尽量使用explain 分析sql语句是很重要的。并且在很多时候注意使用hint,因为即使是执行计划,也不是很可信的。
三) 表格顺序
曾经,有人说,表格的顺序很重要。
我说,没错,但那仅仅是曾经而已,对于10g而言,这些发生了变化。
现在要下两个结论:
1)如果都是inner join(无论是否有明确指定顺序的),那么oracle会自动地在结果集合比较小的那个表格开始执行 (不考虑索引,条件等)。下一个表格是什么则取决于第一表关联的对象,然后才是其它。
例如 select a.*,b*,c* from a,b,c where a.id=b.id and c.id=a.id
select a.*,b*,c* from a join b on b.id=a.id join c on c.id=a.id
2)一切以执行计划为准,但可以通过调整语句来改变执行计划。
http://lzfhope.blog.163.com/blog/static/636399220082214551786/
3.2 DISTINCT|UNIQUE
我们可以希望只返回重复行中的一行,那么可以在语句中设置distinct或者unique.
限制:1)当设置了distinct或者unique的时候,select语句列表中的列所包含的所有字节总数是受到限制的,必须等于数据块的大小减去一些负载信息(不是很明白)?. the total number of bytes in all select list
expressions is limited to the size of a data block minus some overhead 。2)如果列包含了lob,那么不能使用distinct或者unique。
3.9)样品(抽样)语句(sample clause)
使用抽样语句,可以只随机选择一部分数据,而不是所有的数据.包括行随机抽样(sample),以及块随机抽样(block).
语法 select * from tab sample(N) seed(S)
例子:
SQL> select * from test_flashback sample(50);
SID FULLNAME
---------- ----------------------------------------
101 天南地北
SQL> select * from test_flashback sample(50);
SID FULLNAME
---------- ----------------------------------------
101 天南地北
101 五湖四海
SQL> select * from test_flashback sample(50);
SID FULLNAME
---------- ----------------------------------------
101 五湖四海
101 三山五岳
其中函数sample(N),N是在区间[0.000001,100)之内的数,可以称呼为命中率.表格或者视图的数据越多则这个函数的效果越好。这个函数在某些时候还是非常有用的.SEED(S)中的S介于[0,4294967295]之间,该函数主要是用于保证返回的结果集合和前次的同样S取值的一样。
要保证采取块抽取,则可以用 /*+full*/ 或者/*+INDEX_FFS*/的强制提示来执行语句。
限制:1)只有一个视图是包含主键的时候,才可以用抽样语句;2)在DML语句的子查询中不能使用抽样语句.