有一张sentence表记录了发言人的记录
create table sentence
( sentence_id number,
  con_id number,
  speaker_id,
  primary key (sentence_id
)
sentence_id 发言的流水号
con_id  会议的ID
speaker_id 发言人的ID
一个人可以在多个会议上多次发言现在写一条SQL找出仅仅在'101'会议上发过言的人的ID,下面有两种写法
1 select qry.speaker_id as speaker_id from
  ( select count(distinct a.con_id) as con_cnt, a.speaker_id from sentence a,
    (select distinct speaker_id from sentence where con_id = 101) b
    where a.speaker_id=b.speaker_id group by a.speaker_id
  ) qry where qry.con_cnt = 12 select distinct(speaker_id) from sentence where con_id = 1
  minus
  select distinct(speaker_id) from sentence where con_id != 1似乎写法2比较清楚,但是set autotrace on以后,我查看了执行计划,好象写法1的CPU(COST)小一点
写法1和2究竟哪一种比较好,或者还有更好的写法?
应该怎么考虑这个问题?

解决方案 »

  1.   

    不要太追求完美
    测试结果吧2的!= 1应该用的是tableScan吧.
      

  2.   


    select distinct (speaker_id) aa
      from sentence
     where con_id = 101
       and aa not in (select speaker_id from sentence where con_id != 101);
    你的第二条语句思路也很清晰。
      

  3.   

    给你几个SQL书写的准则
    FROM后面的子句 ORACLE是从右向左解析的
    SQL> SELECT COUNT(*) FROM ELXB,S_GJZ;  COUNT(*)
    ----------
        432446已用时间:  00: 00: 01.06
    SQL> SELECT COUNT(*) FROM S_GJZ,ELXB;  COUNT(*)
    ----------
        432446已用时间:  00: 00: 22.09
    所以数据量小的做基础表放最右边
    如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.WHERE 后的子句是自下而上根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾SELECT … FROM EMP E WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO) AND SAL > 50000 AND JOB = 'MANAGER';
    SELECT子句中避免使用 '*' 当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 ‘*' 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间. 
    用EXISTS替代IN 用NOT EXISTS替代NOT IN 用表连接替换EXISTS 
    通常来说 , 采用表连接的方式比EXISTS更有效率 SELECT ENAME FROM EMP E WHERE EXISTS (SELECT ‘X' FROM DEPT WHERE DEPT_NO =E.DEPT_NO AND DEPT_CAT = ‘A'); 
    (更高效) 
    SELECT ENAME FROM DEPT D,EMP E WHERE E.DEPT_NO = D.DEPT_NO AND DEPT_CAT = ‘A' 8.用EXPLAIN PLAN 分析SQL语句(这个方法看你说,你是应该晓得的但是你没必要把所有查询的结果都显示出来)
    set autotrace traceonly /*traceonly 可以不显示执行结果*/ 
    SQL> select gjz from elxb;已选择432446行。已用时间:  00: 00: 11.04Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE
       1    0   TABLE ACCESS (FULL) OF 'ELXB'
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
          35457  consistent gets
              0  physical reads
              0  redo size
        6490016  bytes sent via SQL*Net to client
         317622  bytes received via SQL*Net from client
          28831  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
         432446  rows processed
    我理解掌握的就这么多你在找资料看看吧
      

  4.   

    顶,学习中SELECT ENAME FROM EMP E WHERE EXISTS (SELECT ‘X' FROM DEPT WHERE DEPT_NO =E.DEPT_NO AND DEPT_CAT = ‘A'); 
    (更高效) 
    SELECT ENAME FROM DEPT D,EMP E WHERE E.DEPT_NO = D.DEPT_NO AND DEPT_CAT = ‘A' 那样的话,不是所有的连接都用这种最普通的写法好了,既方便又高效,那IN和EXIST有什么存在的必要呢?
      

  5.   


    2楼的大意了,应该是
    select distinct (speaker_id) aa
      from sentence
     where con_id = 101
       and speaker_id not in (select speaker_id from sentence where con_id != 101);