TABLE_A(aID,bID,cID,a,b,c,d)
TABLE_B(aID,bID,cID,e,f,g,h)两表中,aID,bID,cID 为关联字段
以下两种查询中,哪种是最优的1.
select aID,bID,cID,a,b,c,d,e,f,g,h
from TABLE_A A INNER JOIN TABLE_B B 
               on A.aID=B.aID and A.bID=B.bID and A.cID=B.cID
where  aID='abc123456789' and a='1' and b='abc'
2.
select aID,bID,cID,a,b,c,d,e,f,g,h
from TABLE_A A INNER JOIN TABLE_B B 
               on B.aID='abc123456789' and A.bID=B.bID and A.cID=B.cID
where  aID='abc123456789' and a='1' and b='abc'
个人观点是认为1,因为两个表关联,主要是以字段进行,某一个字段的值是多少,是在where中解决。
并且2破坏了查询的规范性。请有更好的见解,请指出。

解决方案 »

  1.   

    1, 没有任何一种连接方式和执行计划是生来就优越的;
    2,没有表结构及其统计信息的话孰优孰劣是无从判断的;
    3,一个经验原则是这样的:如果where谓词中的过滤性较好,可以考虑走索引,连接方式推荐嵌套循环;
    4,如果where谓词中的过滤性较差,则推荐使用hash连接,全表扫描的方式。
    5,如果希望得到一个查询的实际执行代价,可以使用10046或者autotrace工具
      

  2.   

    要看基于什么优化模式,一般来说,基本COST(成本)的优化方式一般与写法无关,关键根据统计数据来计算成本,成本开销小的为最优路径。并且现在ORACLE推荐成本优化模式。
      

  3.   

    给你个这方面的说明看一下:
    ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并.
    例如:     表 TAB1 16,384 条记录     表 TAB2 1      条记录     选择TAB2作为基础表 (最好的方法)     select count(*) from tab1,tab2   执行时间0.96秒    选择TAB2作为基础表 (不佳的方法)     select count(*) from tab2,tab1   执行时间26.09秒
    如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.
    例如:
       EMP表描述了LOCATION表和CATEGORY表的交集.
     SELECT * 
    FROM LOCATION L , 
          CATEGORY C,      EMP E WHERE E.EMP_NO BETWEEN 1000 AND 2000
    AND E.CAT_NO = C.CAT_NO
    AND E.LOCN = L.LOCN 将比下列SQL更有效率 SELECT * 
    FROM EMP E ,LOCATION L ,       CATEGORY CWHERE  E.CAT_NO = C.CAT_NOAND E.LOCN = L.LOCNAND E.EMP_NO BETWEEN 1000 AND 20005.WHERE子句中的连接顺序.ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.例如:(低效,执行时间156.3秒)SELECT … FROM EMP EWHERE  SAL > 50000AND    JOB = ‘MANAGER’AND    25 < (SELECT COUNT(*) FROM EMP             WHERE MGR=E.EMPNO);(高效,执行时间10.6秒)SELECT … FROM EMP EWHERE 25 < (SELECT COUNT(*) FROM EMP             WHERE MGR=E.EMPNO)AND    SAL > 50000AND    JOB = ‘MANAGER’;
    还有下面关于SQL优化注意的一些方面:
    a) sql的使用规范: 
        i. 尽量避免大事务操作,慎用holdlock子句,提高系统并发能力。 
        ii. 尽量避免反复访问同一张或几张表,尤其是数据量较大的表,
        可以考虑先根据条件提取数据到临时表中,然后再做连接。 
        iii. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,
        那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。 
        iv. 注意where字句写法,必须考虑语句顺序,应该根据索引顺序、范围大小来确定条件子句的前后顺序,
        尽可能的让字段顺序与索引顺序相一致,范围从大到小。 
        v. 不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 
        vi. 尽量使用exists代替select count(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用,
        而且count(1)比count(*)更有效率。 
        vii. 尽量使用“>=”,不要使用“>”。 viii. 注意一些or子句和union子句之间的替换 
        ix. 注意表之间连接的数据类型,避免不同类型数据之间的连接。 
        x. 注意存储过程中参数和数据类型的关系。 
        xi. 注意insert、update操作的数据量,防止与其他应用冲突。如果数据量超过200个数据页面(400k),
        那么系统将会进行锁升级,页级锁会升级成表级锁。 
        b) 索引的使用规范: 
        i. 索引的创建要与应用结合考虑,建议大的oltp表不要超过6个索引。 
        ii. 尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过index index_name来强制指定索引 
        iii. 避免对大表查询时进行table scan,必要时考虑新建索引。 
       1。已经检验的语句和已在共享池中的语句之间要完全一样
    2。变量名称尽量一致
    3。合理使用外联接
    4。少用多层嵌套
    5。多用并发 语句的优化步骤一般有:
    1。调整sga区,使得sga区的是用最优。
    2。sql语句本身的优化,工具有explain,sql trace等
    3。数据库结构调整
    4。项目结构调整
    写语句的经验:
    1。对于大表的查询使用索引
    2、少用in,exist等
    3、使用集合运算1.对于大表查询中的列应尽量避免进行诸如
       To_char,to_date,to_number
       等转换
    2.有索引的尽量用索引,有用到索引的条件写在前面
       如有可能和有必要就建立一些索引 
    3.尽量避免进行全表扫描,限制条件尽可能多,以便更快
       搜索到要查询的数据
      

  4.   

    谢谢各位的热情。
    我在执行计划中看到,在ON中加了那个条件,数据在第一次基表查询时,是会以此条件进行第一次筛选的。
    但并不是说加了那条件就一定是最优的。因为要看此条件的查询数据是否比 on 其它条件和where的条件加起来更少的查询,如果是更好,那么是更优的,如果不是,那就更差。