Oracle查询优化-多表查询

--合并结果集
--1.union all
SELECT * FROM emp WHERE empno=7369
UNION ALL--单纯合并
SELECT * FROM emp WHERE empno=7369;
--2.union
 SELECT * FROM emp WHERE empno=7369
UNION --将重复结果集合并
SELECT * FROM emp WHERE empno=7369;
--------------使用命令窗口执行,查看union与or的执行计划
SQL> alter session set "_b_tree_bitmap_plans" = FALSE;
SQL> explain plan for select empno,ename from emp where empno =7788 or ename=‘SCOTT‘;
SQL> select * from table(dbms_xplan.display);
SQL> explain plan for select empno,ename from emp where empno=7788 UNION select empno,ename from emp where ename = ‘SCOTT‘;
SQL> select * from table(dbms_xplan.display);
--可见union会使用索引
--union会强制将结果集进行合并,从而使数据出现错误
SQL> select empno,deptno from emp where mgr=7698 order by 1;

EMPNO DEPTNO
----- ------
 7499     30
 7521     30
 7654     30
 7844     30
 7900     30

SQL> select empno,deptno from emp where job=‘SALESMAN‘ order by 1;

EMPNO DEPTNO
----- ------
 7499     30
 7521     30
 7654     30
 7844     30
--从上面两条语句看出有4条结果重复,看看union和or的区别
SQL> select deptno from emp where mgr=7698 or job=‘SALESMAN‘;

DEPTNO
------
    30
    30
    30
    30
    30

SQL> select deptno from emp where mgr=7698
  2  union
  3  select deptno from emp where job=‘SALESMAN‘;

DEPTNO
------
    30
/**************************************************************************************************************************************
 * 结论:
 * 1.不仅两个数据集间重复的数据会被去重,而且单个数据集里重复的数据也会被去重;
 * 2.有重复数据的数据集用union后得到的数据与预期会不一致;
 * 3.可以这样,select deptno from (select empno,deptno from emp where mgr=7698 union select empno,deptno from emp where job=‘SALESMAN‘)
 *   或者将empno改为rowid也行。
 **************************************************************************************************************************************/
--4.[inner] join与=
SELECT e.empno,e.ename,d.dname,d.loc
FROM emp e
INNER JOIN dept d ON (e.deptno=d.deptno)
WHERE e.deptno=10;
SELECT e.empno,e.ename,d.dname,d.loc
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND e.deptno=10;--以上两句结果相同,但join是SQL-92标准,可以清晰反应表与表之间的关联关系,推荐使用join
--5.in、exists和inner join
CREATE TABLE emp2 AS--创建相关table
SELECT ename,job,sal,comm FROM emp WHERE job = ‘CLERK‘;
--6.要求查询与emp2相匹配的emp中的数据,可以使用in、exists或inner join
SELECT * FROM emp WHERE (ename,job,sal) IN (SELECT ename,job,sal FROM emp2);
SELECT * FROM emp a WHERE EXISTS (SELECT NULL FROM emp2 b WHERE b.ename=a.ename
                                         AND b.job=a.job
                                         AND b.sal=a.sal);
SELECT * FROM emp a
INNER JOIN emp2 b
ON (b.ename=a.ename
   AND b.job=a.job
   AND b.sal=a.sal);
/********************************************************************************************************
 * 结论:
 * 1.以上三条语句可以返回相同条数的结果集;
 * 2.通过查看plan可以看出,exists和in都使用了HASH JOIN SEMI(哈希半连接)而inner join使用了哈希连接;
 * 3.exists和in的执行效率是一样的,如果不确定,可以通过查看plan来判断,不要死记硬背。
 ********************************************************************************************************/
--7.内、左、右、外连接
--建立测试表
--左表
DROP TABLE L;
CREATE TABLE L AS SELECT ‘L_1‘ AS str,‘1‘ AS v FROM dual UNION ALL
SELECT ‘L_2‘,‘2‘ AS v FROM dual UNION ALL
SELECT ‘L_3‘,‘3‘ AS v FROM dual UNION ALL
SELECT ‘L_4‘,‘4‘ AS v FROM dual;
--右表
DROP TABLE R;
CREATE TABLE R AS
SELECT ‘R_3‘ AS str,‘3‘ AS v,1 AS STATUS FROM dual UNION ALL
SELECT ‘R_4‘,‘4‘ AS v,0 AS STATUS FROM dual UNION ALL
SELECT ‘R_5‘,‘5‘ AS v,0 AS STATUS FROM dual UNION ALL
SELECT ‘R_6‘,‘6‘ AS v,0 AS STATUS FROM dual;
--INNER JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
INNER JOIN r ON l.v=r.v
ORDER BY 1,2;
SELECT l.str AS l_str,r.str AS r_str
FROM l,r
WHERE l.v=r.v
ORDER BY 1,2;
--LEFT JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
LEFT JOIN r ON l.v=r.v
ORDER BY 1,2;
SELECT l.str AS l_str,r.str AS r_str
FROM l,r
WHERE l.v=r.v(+)
ORDER BY 1,2;
--RIGHT JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
RIGHT JOIN r ON l.v=r.v
ORDER BY 1,2;
SELECT l.str AS l_str,r.str AS r_str
FROM l,r
WHERE l.v(+)=r.v
ORDER BY 1,2;
--FULL JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
FULL JOIN r ON l.v=r.v
ORDER BY 1,2;
--8.自连接
SELECT a.empno,a.ename,b.ename mgr,a.deptno FROM emp a,emp b WHERE a.mgr=b.empno(+) ORDER BY a.empno;
--9.NOT IN,NOT EXISTS和LEFT JOIN
SELECT * FROM DEPT WHERE DEPTNO NOT IN(SELECT DEPTNO FROM EMP WHERE EMP.DEPTNO IS NOT NULL);
SELECT * FROM DEPT WHERE NOT EXISTS (SELECT NULL FROM EMP WHERE EMP.DEPTNO = DEPT.DEPTNO);
SELECT DEPT.* FROM DEPT LEFT JOIN EMP ON EMP.DEPTNO=DEPT.DEPTNO WHERE EMP.DEPTNO IS NULL;
--10.外连接中的条件
 --沿用7的测试表,查询左表所有内容,使用V关联右表,但只显示右表中STATUS为1的值,期望结果如下:
STR STR
--- ---
L_1
L_2
L_3 R_3
L_4
--错误写法:
SELECT L.STR,R.STR FROM L LEFT JOIN R ON(L.V=R.V) WHERE R.STATUS=1 ORDER BY 1;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 688663707
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     1 |    27 |     8  (25)| 00:00:01 |
|   1 |  SORT ORDER BY      |      |     1 |    27 |     8  (25)| 00:00:01 |
|*  2 |   HASH JOIN         |      |     1 |    27 |     7  (15)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL| R    |     1 |    21 |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| L    |     4 |    24 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("L"."V"="R"."V")
   3 - filter("R"."STATUS"=1)
Note
-----

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
   - dynamic sampling used for this statement

21 rows selected
--正确写法:
SELECT L.STR,R.STR FROM L LEFT JOIN R ON (L.V=R.V AND R.STATUS=1) ORDER BY 1;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2310059642
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     4 |   108 |     8  (25)| 00:00:01 |
|   1 |  SORT ORDER BY      |      |     4 |   108 |     8  (25)| 00:00:01 |
|*  2 |   HASH JOIN OUTER   |      |     4 |   108 |     7  (15)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| L    |     4 |    24 |     3   (0)| 00:00:01 |
|*  4 |    TABLE ACCESS FULL| R    |     1 |    21 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("L"."V"="R"."V"(+))
   4 - filter("R"."STATUS"(+)=1)
Note
-----

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
   - dynamic sampling used for this statement

21 rows selected
/*外层条件不要随便加,会影响结果集*/
--11.检测两个表中的数据及对应数据的条数是否相同
CREATE OR REPLACE VIEW V AS
SELECT * FROM EMP WHERE DEPTNO != 10
UNION ALL
SELECT * FROM EMP WHERE ENAME=‘SCOTT‘;
--要求查处视图V与表EMP中不同的数据(注意:视图中‘SCOTT‘有两行数据,而EMP表中只有一条数据)
--分析:除了EMP表中DEPTNO为10的数据,还有ENAME为SCOTT的数据与V中不一致,因为EMP表中只有一条而V中有两条
SELECT *
FROM (SELECT EMPNO,ENAME,COUNT(*) AS CNT FROM V GROUP BY EMPNO,ENAME) V --加一列统计条数用以区分不同
FULL JOIN (SELECT EMPNO,ENAME,COUNT(*) AS CNT FROM EMP GROUP BY EMPNO,ENAME) E
ON V.EMPNO=E.EMPNO AND V.CNT=E.CNT
WHERE V.EMPNO IS NULL OR E.EMPNO IS NULL;
     EMPNO ENAME             CNT EMPNO ENAME             CNT
---------- ---------- ---------- ----- ---------- ----------
      7788 SCOTT               2
                                  7782 CLARK               1
                                  7839 KING                1
                                  7788 SCOTT               1
                                  7934 MILLER              1
--12.聚集与内连接
CREATE TABLE EMP_BONUS (EMPNO INT,RECEIVED DATE,TYPE INT);
INSERT INTO EMP_BONUS VALUES (7934,DATE ‘2005-5-17‘,1);
INSERT INTO EMP_BONUS VALUES (7934,DATE ‘2005-2-15‘,2);
INSERT INTO EMP_BONUS VALUES (7839,DATE ‘2005-5-17‘,3);
INSERT INTO EMP_BONUS VALUES (7782,DATE ‘2005-5-17‘,1);
--要求返回上述员工的工资及奖金,奖金根据TYPE来定,TYPE为1,奖金为10%...
SELECT E.DEPTNO,E.EMPNO,E.ENAME,E.SAL,B.TYPE*0.1*E.SAL AS BONUS
FROM EMP E,EMP_BONUS B
WHERE E.EMPNO(+)=B.EMPNO;
DEPTNO EMPNO ENAME            SAL      BONUS
------ ----- ---------- --------- ----------
    10  7934 MILLER       1300.00        130
    10  7934 MILLER       1300.00        260
    10  7839 KING         5000.00       1500
    10  7782 CLARK        2450.00        245
--若此时想要计算6月份部门为10的总工资
    --错误做法:
    SELECT E.DEPTNO,SUM(E.SAL) TOTAL_SAL,SUM(B.TYPE*0.1*E.SAL) AS TOTAL_BONUS
    FROM EMP E,EMP_BONUS B
    WHERE E.EMPNO(+)=B.EMPNO
    GROUP BY E.DEPTNO;
    DEPTNO  TOTAL_SAL TOTAL_BONUS
    ------ ---------- -----------
        10      10050        2135
    --原因,MILLER的工资和奖金都重复计算了,因为他5月份已经降职了,所以有两条不同的TYPE对应他的相关信息!
    --正确做法:
    SELECT E.DEPTNO,SUM(E.SAL) TOTAL_SAL,SUM(B.TYPE*0.1*E.SAL) AS TOTAL_BONUS
    FROM EMP E
    INNER JOIN
    (SELECT EB.EMPNO,EB.TYPE,EB.RECEIVED
            FROM EMP_BONUS EB
            INNER JOIN
            (SELECT MAX(C.EMPNO) EMPNO,MAX(C.RECEIVED) RECEIVED FROM EMP_BONUS C GROUP BY C.EMPNO) EBG --先统计出员工最新的职位变更时间
            ON EB.EMPNO=EBG.EMPNO AND EB.RECEIVED=EBG.RECEIVED) B
    ON E.EMPNO=B.EMPNO
    GROUP BY E.DEPTNO;
DEPTNO  TOTAL_SAL TOTAL_BONUS
------ ---------- -----------
    10       8750        1875
--13.聚集与外连接
    SELECT E.DEPTNO,SUM(E.SAL) TOTAL_SAL,SUM(B.TYPE*0.1*E.SAL) AS TOTAL_BONUS
    FROM EMP E
    LEFT JOIN --只改此处为LEFT JOIN即可
    (SELECT EB.EMPNO,EB.TYPE,EB.RECEIVED
            FROM EMP_BONUS EB
            INNER JOIN
            (SELECT MAX(C.EMPNO) EMPNO,MAX(C.RECEIVED) RECEIVED FROM EMP_BONUS C GROUP BY C.EMPNO) EBG --先统计出员工最新的职位变更时间
            ON EB.EMPNO=EBG.EMPNO AND EB.RECEIVED=EBG.RECEIVED) B
    ON E.EMPNO=B.EMPNO
    GROUP BY E.DEPTNO
    ORDER BY 1;
DEPTNO  TOTAL_SAL TOTAL_BONUS
------ ---------- -----------
    10       8750        1875
    20      10875
    30       9400
--14.多表查询时的空值处理
    --要求返回比ALLEN提成低的员工
    --错误做法:
SELECT E.ENAME,E.COMM
FROM EMP E
WHERE E.COMM<(SELECT COMM FROM EMP WHERE ENAME=‘ALLEN‘);
ENAME           COMM
---------- ---------
TURNER          0.00
    --错误原因:有些员工的COMM一项为NULL,但并未返回
    --正确做法:
SELECT E.ENAME,E.COMM
FROM EMP E
WHERE COALESCE(E.COMM,0)<(SELECT COMM FROM EMP WHERE ENAME=‘ALLEN‘);
ENAME           COMM
---------- ---------
SMITH
JONES
BLAKE
CLARK
SCOTT
KING
TURNER          0.00
ADAMS
JAMES
FORD
MILLER   
时间: 2024-10-14 10:40:28

Oracle查询优化-多表查询的相关文章

Oracle数据库锁表查询以及解锁进程

Oracle数据库操作中,我们有时会用到锁表查询以及解锁和kill进程等操作,那么这些操作是怎么实现的呢?本文我们主要就介绍一下这部分内容. 锁表查询的代码有以下的形式: select count(*) from v$locked_object; select * from v$locked_object; 查看哪个表被锁 1.select b.owner,b.object_name,a.session_id,a.locked_mode 2. from v$locked_object a,dba

Oracle的单表查询语句

使用Oracle 数据库的测试表单: --单表查询数据 语法 select (查询) * 所有 /查询的字段,多个字段 ,隔开 from (来自) 表名称 --查询所有员工的信息 select * from scott.emp; select * from dept; --查询所有员工的编号,姓名和职位 指定字段名查找数据 select empno,ename,job from emp; --查询所有员工的编号,姓名和年薪 select * from emp; select empno,enam

ORACLE EBS常用表查询语句

1. OU.库存组织 SELECT hou.organization_id ou_org_id, --org_id hou.name ou_name, --ou 名称 ood.organization_id org_org_id, -- 库存组织 id ood.organization_code org_org_code, -- 库存组织代码 msi.secondary_inventory_name, -- 子库存名称 msi.description -- 子库存描述 FROM hr_organ

oracle的多表查询与表的连接

一.多表查询 在任何多表查询中一定会产生笛卡尔积的问题,但是,笛卡尔积产生的结果对于用户来说是毫无意义的,是重复的无用数据.因此我们需要消除笛卡尔积,那么在多表查询的时候,就必须要有关联字段. 范例:emp.deptno=dept.deptno;两张表中的关联字段将消除笛卡尔积 SELECT * FROM emp, dept WHERE emp.deptno=dept.deptno; 多表的查询,建议多做些习题增加熟练度. 二.表的连接 内连接:之前利用了WHERE子句消除了笛卡尔积,这个是内连

mysql 查询优化 ~ 多表查询改写思路

一 简介:在之前我们从基础可知,现在咱们聊一下改写的几种思路二 分类:  1 left join  2 inner join  3 right join三 具体改写思路:思路1 本身不包含子查询,将多表查询的条件拆分成多个select子查询然后再进行关联思路2 本身涉及到分组,增加order by null,去掉文件排序,减少消耗思路3 本身驱动表选择不正确,增加STRAIGHT_JOIN进行强制指定驱动表待补充 只代表个人观点 原文地址:https://www.cnblogs.com/danh

oracle查询优化之子查询条件优化

环境:oracle 11g 现有a表与b表通过a01字段关联,要查询出a表的数据在b表没有数据的数据:sql如下 select count(1) from (select a.*,(select count(1) from b where b.a01=a.a01) as flag from a) where flag=0 因为flag是虚拟字段没有走不了索引导致这条sql执行起来特别慢 310W条数据查总数花费2秒左右. 利用not exists优化sql如下 select count(1) f

Oracle数据库锁表查询

--查看数据库最大连接数 select value from v$parameter where name = 'processes'; --更改数据库连接数 alter system set processes = 3000 scope = spfile; --查看被锁的表 select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_objects b where b.object_id

【Oracle】锁表查询与解锁

在PL/SQL中执行以下内容: 如下语句 查询锁定的表: SELECT l.session_id sid, s.serial#, l.locked_mode,l.oracle_username, l.os_user_name,s.machine, s.terminal, o.object_name, s.logon_time FROM v$locked_object l, all_objects o, v$session s WHERE l.object_id = o.object_id AND

Oracle【多表查询操作(SQL92&amp;SQL99)】

多表联合查询:需要获取的数据分布在多张表中 SQL92: 1 --笛卡尔积:将多个表的数据进行一一对应,所得的结果为多表的笛卡尔积 2 select * from emp; 3 select * from dept; 4 select * from emp,dept;--进行全排列 14*5=70 1 --等值连接:先笛卡尔积,然后筛选,筛选条件为等值筛选 2 --查询员工的姓名,工作,薪资,部门名称 3 --可直接在select子句中使用字段获取数据,但效率低,建议字段前明确表名 4 sele