select * from A,B 和 select * from B,A,在整体上来看结果是相同的,但从局部来看,A*B是用A的第一行去和B的每一行结合,结合完毕后再用A的第二行和B的每一行结合,以此类推。而B*A是用B的第一行和A的每一行结合,结合完毕后再用B的第二行和A的每一行结合。都是同样的一个的SELECT,实在让人很想不通…… 能帮解释下?谢谢了!
调试欢乐多
笛卡尔积定义
设A,B为集合,用A中元素为第一元素,B中元素为第二元素构成的有序对,所有这样的有序对组成的集合
叫做A与B的笛卡尔积,记作AxB.上面有一个很关键的词为“有序”,因此,我们来看一个例子:
例如,A={a,b},B={0,1,2},则
AxB={<a,o>,<a,1>,<a,2>,<b,0>,<b,1>,<b,2>,}
BxA={<0,a>,<0,b>,<1,a>,<1,b>,<2,a>,<2,b>}因此,一般地说,笛卡尔积运算不满足交换律,即AxB≠BxA因此,在回来看楼主的sql文,oracle根据表的先后顺序不同,其解析表的顺序也不同,基表的顺序会不一样,产生的笛卡尔积会出现楼主看到的现象,其实是很正常的。请安心~
表 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 C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000 2.WHERE子句中的连接顺序. ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. 例如: --(低效,执行时间156.3秒)
SELECT …
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER’
AND 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO); --(高效,执行时间10.6秒)
SELECT …
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER’; 3.SELECT子句中避免使用 '*'当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 '*' 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将'*'依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.
4.用EXISTS替代IN
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率. --低效:
SELECT *
FROM EMP (基础表)
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC = ‘MELB’)
--高效:
SELECT *
FROM EMP (基础表)
WHERE EMPNO > 0
AND EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ‘MELB’)