------测试了下,从左往右执行。。呵呵。 SQL> select * from dual where 1?=2 and 1=1 and 3?=2; select * from dual where 1?=2 and 1=1 and 3?=2 * 第 1 行出现错误: ORA-00911: 无效字符
--解析都是从右往左解析的 scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNOQ=10 AND LOCT='BOSTON'; SELECT * FROM DEPT WHERE DEPTNOQ=10 AND LOCT='BOSTON' * 第 1 行出现错误: ORA-00904: "LOCT": 标识符无效 --上面where条件的两个字段名都是错误的 提示loct无效scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNO1=10 AND LOC='BOSTON'; SELECT * FROM DEPT WHERE DEPTNO1=10 AND LOC='BOSTON' * 第 1 行出现错误: ORA-00904: "DEPTNO1": 标识符无效 --上面where条件的loc字段是正确的 提示deptno1无效scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOC='BOSTON'; SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOC='BOSTON' * 第 1 行出现错误: ORA-00904: "DEPTNO1": 标识符无效 scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOCA='BOSTON'; SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOCA='BOSTON' * 第 1 行出现错误: ORA-00904: "LOCA": 标识符无效
从右到左… 如果表上有索引例如索引顺序( a,b,c) 那么 尽量写成 where a =? and b= ? and c= ? and d = ?好像oracle9之后 顺序写反了 ORACLE也能利用到索引, 但是还是需要花费一定的时间,所以还是一次写好的好.尽量把能过滤的大条件写在后面 如标志,男女等.
建表; create table t_testcolstart as select * from dba_objects; 插入数据: insert into t_testcolstart select * from t_testcolstart; commit; insert into t_testcolstart select * from t_testcolstart; commit; insert into t_testcolstart select * from t_testcolstart; commit; insert into t_testcolstart select * from t_testcolstart; commit; insert into t_testcolstart select * from t_testcolstart; commit; insert into t_testcolstart select * from t_testcolstart; commit; SQL> select count(*) from t_testcolstart; COUNT(*) ---------- 807088
--目前表中以及包含近百万数据--构造条件,测试数据数据一: SQL> select * from t_testcolstart a where a.owner = 'HAHA' and a.object_name = 'HAHA'; 已用时间: 00: 00: 00.06 SQL> select * from t_testcolstart a where a.object_name = 'HAHA' and a.owner = 'HAHA';已用时间: 00: 00: 00.07 SQL> select * from t_testcolstart a where a.owner = 'HAHA'; 已用时间: 00: 00: 00.06 SQL> select * from t_testcolstart a where a.object_name = 'HAHA'; 已用时间: 00: 00: 00.06几乎看不出什么差距测试二: SQL> select * from t_testcolstart a where a.owner = 'HAHA' and instr(a.object_name,'123') = 1; b1 已用时间: 00: 00: 00.07 SQL> select * from t_testcolstart a where instr(a.object_name,'123') = 1 and a.owner = 'HAHA'; b2 已用时间: 00: 00: 00.06SQL> select * from t_testcolstart a where instr(a.object_name,'123') = 1; b3 已用时间: 00: 00: 00.31从本组数据我们可以看到 b1 与b2在查询的时候 都忽略了 instr(a.object_name,'123'), 不管其位与什么地方,都是先执行的 owner条件, 也就可以推出 oracle默认是先比较 干净的字段,后比较带函数的字段,并且实行了短路原则,只要第一个比较结果为否,后续都不会比较测试三 SQL> select * from t_testcolstart a where substr(a.object_type,2,4) = 'HAHA' and instr(a.owner,'123') = 1; c1 已用时间: 00: 00: 00.29 SQL> select * from t_testcolstart a where instr(a.owner,'123') = 1 and substr(a.object_type,2,4) = 'HAHA'; c2 已用时间: 00: 00: 00.24 SQL> select * from t_testcolstart a where instr(a.owner,'123') = 1 ; c3 已用时间: 00: 00: 00.23 SQL> select * from t_testcolstart a where substr(a.object_type,2,4) = 'HAHA'; c4 已用时间: 00: 00: 00.29从本组数据 我们可以看到 c1与c4相差不多, c2与c3相差不多,也就可以推出 where 执行的过程是从左到右测试四 为了验证结论三 ,再测试一组数据 SQL> select * from t_testcolstart a where substr(a.owner,2,4) = 'HAHA' and instr(a.object_type,'123') = 1; d1已用时间: 00: 00: 00.29 SQL> select * from t_testcolstart a where instr(a.object_type,'123') = 1 and substr(a.owner,2,4) = 'HAHA'; d2已用时间: 00: 00: 00.23 SQL> select * from t_testcolstart a where instr(a.object_type,'123') = 1 ; d3已用时间: 00: 00: 00.23 SQL> select * from t_testcolstart a where substr(a.owner,2,4) = 'HAHA'; d4已用时间: 00: 00: 00.30明显可以看出where执行条件是从左到右,并且可以看出instr 的效率要比substr好一点
好吧,你自己都说了,优化器都不知道a=5和b=6应该先执行哪个,那你凭什么知道呢? 在a=1 and b=2 and c=3 这种绝对平衡的where条件中(所谓绝对平衡是指数据分布,返回结果,执行方式等效率全部一样),CBO怎么执行的,有必要去考虑吗,怎么执行的结果都一样。如果where条件不平衡,同样不用考虑先后顺序,因为CBO会把所有where条件平等看待,无所谓先后。
------测试了下,从左往右执行。。呵呵。
SQL> select * from dual where 1?=2 and 1=1 and 3?=2;
select * from dual where 1?=2 and 1=1 and 3?=2
*
第 1 行出现错误:
ORA-00911: 无效字符
不知道oracle是否对and谓词执行顺序可以动态调整,如果是那样,就更无定论了。
scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNOQ=10 AND LOCT='BOSTON';
SELECT * FROM DEPT WHERE DEPTNOQ=10 AND LOCT='BOSTON'
*
第 1 行出现错误:
ORA-00904: "LOCT": 标识符无效
--上面where条件的两个字段名都是错误的 提示loct无效scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNO1=10 AND LOC='BOSTON';
SELECT * FROM DEPT WHERE DEPTNO1=10 AND LOC='BOSTON'
*
第 1 行出现错误:
ORA-00904: "DEPTNO1": 标识符无效
--上面where条件的loc字段是正确的 提示deptno1无效scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOC='BOSTON';
SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOC='BOSTON'
*
第 1 行出现错误:
ORA-00904: "DEPTNO1": 标识符无效
scott@YPCOST> SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOCA='BOSTON';
SELECT * FROM DEPT WHERE DEPTNO1=10 OR LOCA='BOSTON'
*
第 1 行出现错误:
ORA-00904: "LOCA": 标识符无效
如果表上有索引例如索引顺序( a,b,c) 那么 尽量写成 where a =? and b= ? and c= ? and d = ?好像oracle9之后 顺序写反了 ORACLE也能利用到索引, 但是还是需要花费一定的时间,所以还是一次写好的好.尽量把能过滤的大条件写在后面 如标志,男女等.
对于rbo来说,一般建议把过滤量大的语句写在后面,但10g后已经自动进行cbo统计了,不用过多考虑条件的放置顺序了
cbo模式下?
感觉应该根据自己对表数据的理解,加ordered提示
客户端发sql文到ORACLE数据库的时候
是按以下步骤来执行的
1。检查sql语法错误(包括字段之类的存在性)。
2。解析(分为两种 SOFT PARSE和HARD PARSE),如果先前已经有同样的sql文执行过了的话会采用先前的执行计划。如果是第一次执行的sql,会根据统计情报和index等结构来建立最佳的执行计划。这时候ORACLE会根据整个WHERE条件来判断最佳的执行计划。
3。根据第二步的解析结果去找相应的数据块,作最后的数据更改处理。
create table t_testcolstart as select * from dba_objects;
插入数据:
insert into t_testcolstart select * from t_testcolstart;
commit;
insert into t_testcolstart select * from t_testcolstart;
commit;
insert into t_testcolstart select * from t_testcolstart;
commit;
insert into t_testcolstart select * from t_testcolstart;
commit;
insert into t_testcolstart select * from t_testcolstart;
commit;
insert into t_testcolstart select * from t_testcolstart;
commit;
SQL> select count(*) from t_testcolstart; COUNT(*)
----------
807088
--目前表中以及包含近百万数据--构造条件,测试数据数据一:
SQL> select * from t_testcolstart a where a.owner = 'HAHA' and a.object_name = 'HAHA';
已用时间: 00: 00: 00.06
SQL> select * from t_testcolstart a where a.object_name = 'HAHA' and a.owner = 'HAHA';已用时间: 00: 00: 00.07
SQL> select * from t_testcolstart a where a.owner = 'HAHA';
已用时间: 00: 00: 00.06
SQL> select * from t_testcolstart a where a.object_name = 'HAHA';
已用时间: 00: 00: 00.06几乎看不出什么差距测试二:
SQL> select * from t_testcolstart a where a.owner = 'HAHA' and instr(a.object_name,'123') = 1; b1
已用时间: 00: 00: 00.07
SQL> select * from t_testcolstart a where instr(a.object_name,'123') = 1 and a.owner = 'HAHA'; b2
已用时间: 00: 00: 00.06SQL> select * from t_testcolstart a where instr(a.object_name,'123') = 1; b3
已用时间: 00: 00: 00.31从本组数据我们可以看到 b1 与b2在查询的时候 都忽略了 instr(a.object_name,'123'), 不管其位与什么地方,都是先执行的 owner条件,
也就可以推出 oracle默认是先比较 干净的字段,后比较带函数的字段,并且实行了短路原则,只要第一个比较结果为否,后续都不会比较测试三 SQL> select * from t_testcolstart a where substr(a.object_type,2,4) = 'HAHA' and instr(a.owner,'123') = 1; c1
已用时间: 00: 00: 00.29
SQL> select * from t_testcolstart a where instr(a.owner,'123') = 1 and substr(a.object_type,2,4) = 'HAHA'; c2
已用时间: 00: 00: 00.24
SQL> select * from t_testcolstart a where instr(a.owner,'123') = 1 ; c3
已用时间: 00: 00: 00.23
SQL> select * from t_testcolstart a where substr(a.object_type,2,4) = 'HAHA'; c4
已用时间: 00: 00: 00.29从本组数据 我们可以看到 c1与c4相差不多, c2与c3相差不多,也就可以推出 where 执行的过程是从左到右测试四 为了验证结论三 ,再测试一组数据
SQL> select * from t_testcolstart a where substr(a.owner,2,4) = 'HAHA' and instr(a.object_type,'123') = 1; d1已用时间: 00: 00: 00.29
SQL> select * from t_testcolstart a where instr(a.object_type,'123') = 1 and substr(a.owner,2,4) = 'HAHA'; d2已用时间: 00: 00: 00.23
SQL> select * from t_testcolstart a where instr(a.object_type,'123') = 1 ; d3已用时间: 00: 00: 00.23
SQL> select * from t_testcolstart a where substr(a.owner,2,4) = 'HAHA'; d4已用时间: 00: 00: 00.30明显可以看出where执行条件是从左到右,并且可以看出instr 的效率要比substr好一点
37L的钻研精神值得肯定,不过你这个测试第一样本量不足,第二方法也有问题,CBO的具体工作过程我不清楚,但是对于where条件,一定是优先选择执行扫描成本低,返回记录少的条件,比如where条件如果能使用到分区或者索引,那么不管你把相应的where条件写在前面还是后面,它都会首先执行.
你以为优化器是万能的?请你告诉我 在比较 a = 5 与 b= 6 这个过程中 哪个成本最低?
CBO在计算成本的时候大多考虑的是I/O方面的,cpu方面的就比较少就lz的提问而言,我们假设的条件是a.b.c.d这四个条件都是一样的,都不会走索引,也就是在进行全表扫描的情况下而比较的,I/O成本已不再考虑范围内。讨论这个最主要的作用在于使用短路原则,减少CPU进行比较的次数,其并不会减少I/O的产生,当然在大多数情况下,根据大数吃小数的原则,cpu的计算成本相比较I/O是微乎其微的.
另外我的测试虽然样本不足,但就选定的样本而言也是经过多次测试(不下于40次)的比较才得到的结果,至少可以可以看出oracle在这个样本方面所选用的算法
好吧,你自己都说了,优化器都不知道a=5和b=6应该先执行哪个,那你凭什么知道呢?
在a=1 and b=2 and c=3 这种绝对平衡的where条件中(所谓绝对平衡是指数据分布,返回结果,执行方式等效率全部一样),CBO怎么执行的,有必要去考虑吗,怎么执行的结果都一样。如果where条件不平衡,同样不用考虑先后顺序,因为CBO会把所有where条件平等看待,无所谓先后。