by 구루비스터디 쿼리 변환 Query Transformation LEADING INLINE MATERIALIZE Complex View Merging Pushing Predicates NO_PUSH_PRED [2023.09.23]
CREATE TABLE PARENT(ID1 NUMBER NOT NULL,
SMALL_VC1 VARCHAR2(10),
SMALL_VC2 VARCHAR2(10),
PADDING VARCHAR2(200),
CONSTRAINT PAR_PK PRIMARY KEY(ID1));
CREATE TABLE CHILD(ID1 NUMBER NOT NULL,
ID2 NUMBER NOT NULL,
SMALL_VC1 VARCHAR2(10),
SMALL_VC2 VARCHAR2(10),
PADDING VARCHAR2(200),
CONSTRAINT CHI_PK PRIMARY KEY (ID1,ID2));
CREATE TABLE SUBTEST (ID1 NUMBER NOT NULL,
SMALL_VC1 VARCHAR2(10),
SMALL_VC2 VARCHAR2(10),
PADDING VARCHAR2(200),
CONSTRAINT SUB_PK PRIMARY KEY(ID1));
INSERT INTO PARENT
SELECT ROWNUM,
TO_CHAR(ROWNUM),
TO_CHAR(ROWNUM),
RPAD(TO_CHAR(ROWNUM), 100)
FROM ALL_OBJECTS
WHERE ROWNUM <= 3000;
COMMIT;
BEGIN
FOR I IN 1..8 LOOP
INSERT INTO CHILD
SELECT ROWNUM,
I,
TO_CHAR(ROWNUM),
TO_CHAR(ROWNUM),
RPAD(TO_CHAR(ROWNUM), 100)
FROM PARENT;
COMMIT;
END LOOP;
END;
/
INSERT INTO SUBTEST
SELECT * FROM PARENT;
COMMIT;
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(USER,
'PARENT',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(USER,
'CHILD',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(USER,
'SUBTEST',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
END;
/
-- 8i version. subquery postponed
ALTER SESSION SET OPTIMIZER_FEATURES_ENABLE = '8.1.7';
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT PAR.SMALL_VC1,
CHI.SMALL_VC1
FROM PARENT PAR,
CHILD CHI
WHERE CHI.ID1 = PAR.ID1
AND PAR.ID1 BETWEEN 100
AND 200
AND EXISTS (SELECT NULL
FROM SUBTEST SUB
WHERE SUB.SMALL_VC1 = PAR.SMALL_VC1
AND SUB.ID1 = PAR.ID1
AND SUB.SMALL_VC2 >= '2');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('40t7w69g69dj7', NULL, 'ALLSTATS COST LAST'));
----------------------------------------------------------------------------------
| Id | Operation | Name | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------
|* 1 | FILTER | | 8 |00:00:00.01 | 1224 |
| 2 | TABLE ACCESS BY INDEX ROWID | CHILD | 808 |00:00:00.01 | 921 |
| 3 | NESTED LOOPS | | 910 |00:00:00.01 | 113 |
| 4 | TABLE ACCESS BY INDEX ROWID| PARENT | 101 |00:00:00.01 | 6 |
|* 5 | INDEX RANGE SCAN | PAR_PK | 101 |00:00:00.01 | 3 |
|* 6 | INDEX RANGE SCAN | CHI_PK | 808 |00:00:00.01 | 107 |
|* 7 | TABLE ACCESS BY INDEX ROWID | SUBTEST | 1 |00:00:00.01 | 303 |
|* 8 | INDEX UNIQUE SCAN | SUB_PK | 101 |00:00:00.01 | 202 |
----------------------------------------------------------------------------------
-- 8i version. early subquery
-- PUSH_SUBQ, NO_UNNEST 힌트를 사용해도 PAR -> SUB -> CHI 액세스 순서로 유도가
-- 안되서 ROWNUM 방법을 사용함
ALTER SESSION SET OPTIMIZER_FEATURES_ENABLE = '8.1.7';
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT TEMP.SMALL_VC1,
CHI.SMALL_VC1
FROM (SELECT /*+ PUSH_SUBQ */
PAR.SMALL_VC1,
PAR.ID1,
ROWNUM
FROM PARENT PAR
WHERE PAR.ID1 BETWEEN 100
AND 200
AND EXISTS (SELECT /*+ NO_UNNEST */
NULL
FROM SUBTEST SUB
WHERE SUB.SMALL_VC1 = PAR.SMALL_VC1
AND SUB.ID1 = PAR.ID1
AND SUB.SMALL_VC2 >= '2')) TEMP,
CHILD CHI
WHERE TEMP.ID1 = CHI.ID1
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('8qd5asmzzzytm', NULL, 'ALLSTATS COST LAST'));
------------------------------------------------------------------------------------
| Id | Operation | Name | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | CHILD | 8 |00:00:00.01 | 320 |
| 2 | NESTED LOOPS | | 10 |00:00:00.02 | 312 |
| 3 | VIEW | | 1 |00:00:00.01 | 309 |
| 4 | COUNT | | 1 |00:00:00.01 | 309 |
|* 5 | FILTER | | 1 |00:00:00.01 | 309 |
| 6 | TABLE ACCESS BY INDEX ROWID| PARENT | 101 |00:00:00.01 | 6 |
|* 7 | INDEX RANGE SCAN | PAR_PK | 101 |00:00:00.01 | 3 |
|* 8 | TABLE ACCESS BY INDEX ROWID| SUBTEST | 1 |00:00:00.01 | 303 |
|* 9 | INDEX UNIQUE SCAN | SUB_PK | 101 |00:00:00.01 | 202 |
|* 10 | INDEX RANGE SCAN | CHI_PK | 8 |00:00:00.01 | 3 |
------------------------------------------------------------------------------------
;
-- 10g version. subquery postponed
ALTER SESSION SET OPTIMIZER_FEATURES_ENABLE = '10.2.0.3';
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ LEADING(PAR CHI) USE_NL(PAR CHI) */
PAR.SMALL_VC1,
CHI.SMALL_VC1
FROM PARENT PAR,
CHILD CHI
WHERE CHI.ID1 = PAR.ID1
AND PAR.ID1 BETWEEN 100
AND 200
AND EXISTS (SELECT /*+ NO_UNNEST */
NULL
FROM SUBTEST SUB
WHERE SUB.SMALL_VC1 = PAR.SMALL_VC1
AND SUB.ID1 = PAR.ID1
AND SUB.SMALL_VC2 >= '2');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('1h7kqmbwjcf2s', NULL, 'ALLSTATS COST LAST'));
----------------------------------------------------------------------------------
| Id | Operation | Name | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------
|* 1 | FILTER | | 8 |00:00:00.01 | 1224 |
| 2 | TABLE ACCESS BY INDEX ROWID | CHILD | 808 |00:00:00.01 | 921 |
| 3 | NESTED LOOPS | | 910 |00:00:00.01 | 113 |
| 4 | TABLE ACCESS BY INDEX ROWID| PARENT | 101 |00:00:00.01 | 6 |
|* 5 | INDEX RANGE SCAN | PAR_PK | 101 |00:00:00.01 | 3 |
|* 6 | INDEX RANGE SCAN | CHI_PK | 808 |00:00:00.01 | 107 |
|* 7 | TABLE ACCESS BY INDEX ROWID | SUBTEST | 1 |00:00:00.01 | 303 |
|* 8 | INDEX UNIQUE SCAN | SUB_PK | 101 |00:00:00.01 | 202 |
----------------------------------------------------------------------------------
-- 10g version. early subquery
ALTER SESSION SET OPTIMIZER_FEATURES_ENABLE = '10.2.0.3';
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ LEADING(PAR) */
PAR.SMALL_VC1,
CHI.SMALL_VC1
FROM PARENT PAR,
CHILD CHI
WHERE CHI.ID1 = PAR.ID1
AND PAR.ID1 BETWEEN 100
AND 200
AND EXISTS (SELECT /*+ USE_NL(SUB) */
NULL
FROM SUBTEST SUB
WHERE SUB.SMALL_VC1 = PAR.SMALL_VC1
AND SUB.ID1 = PAR.ID1
AND SUB.SMALL_VC2 >= '2');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('4wv1jvg8nra6v', NULL, 'ALLSTATS COST LAST'));
----------------------------------------------------------------------------------
| Id | Operation | Name | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | CHILD | 8 |00:00:00.01 | 221 |
| 2 | NESTED LOOPS | | 10 |00:00:00.01 | 213 |
| 3 | NESTED LOOPS SEMI | | 1 |00:00:00.01 | 210 |
| 4 | TABLE ACCESS BY INDEX ROWID| PARENT | 101 |00:00:00.01 | 6 |
|* 5 | INDEX RANGE SCAN | PAR_PK | 101 |00:00:00.01 | 3 |
|* 6 | TABLE ACCESS BY INDEX ROWID| SUBTEST | 1 |00:00:00.01 | 204 |
|* 7 | INDEX UNIQUE SCAN | SUB_PK | 101 |00:00:00.01 | 103 |
|* 8 | INDEX RANGE SCAN | CHI_PK | 8 |00:00:00.01 | 3 |
----------------------------------------------------------------------------------
;
DROP TABLE EMP;
DROP TABLE GENERATOR;
CREATE TABLE GENERATOR AS
SELECT ROWNUM ID
FROM ALL_OBJECTS
WHERE ROWNUM <= 1000;
CREATE TABLE EMP(DEPT_NO NOT NULL,
SAL,
EMP_NO NOT NULL,
PADDING,
CONSTRAINT E_PK PRIMARY KEY(EMP_NO)
)
AS
SELECT /*+ ORDERED USE_NL(V2) */
MOD(ROWNUM, 6),
ROWNUM,
ROWNUM,
RPAD('X', 60)
FROM GENERATOR V1,
GENERATOR V2
WHERE ROWNUM <= 20000
;
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME => 'EMP',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT =>'FOR ALL COLUMNS SIZE 1');
END;
/
EXPLAIN PLAN FOR
SELECT COUNT(AV_SAL)
FROM (SELECT /*+ NO_MERGE */
OUTER.DEPT_NO,
OUTER.SAL,
OUTER.EMP_NO,
OUTER.PADDING,
(SELECT AVG(INNER.SAL)
FROM EMP
INNER WHERE INNER.DEPT_NO = OUTER.DEPT_NO) AV_SAL
FROM EMP OUTER)
WHERE SAL > AV_SAL
;
@XPLAN;
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 129 (1)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
| 2 | VIEW | | 20000 | 507K| 129 (1)| 00:00:02 |
|* 3 | FILTER | | | | | |
| 4 | TABLE ACCESS FULL | EMP | 20000 | 156K| 65 (2)| 00:00:01 |
| 5 | SORT AGGREGATE | | 1 | 8 | | |
|* 6 | TABLE ACCESS FULL| EMP | 3333 | 26664 | 65 (2)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("OUTER"."SAL"> (SELECT AVG("INNER"."SAL") FROM "EMP"
"INNER" WHERE "INNER"."DEPT_NO"=:B1))
6 - filter("INNER"."DEPT_NO"=:B1)
EXPLAIN PLAN FOR
SELECT COUNT(AV_SAL)
FROM (SELECT /*+ NO_MERGE */
OUTER.DEPT_NO,
OUTER.SAL,
OUTER.EMP_NO,
OUTER.PADDING,
(SELECT AVG(INNER.SAL)
FROM EMP
INNER WHERE INNER.DEPT_NO = OUTER.DEPT_NO) AV_SAL
FROM EMP OUTER)
--WHERE SAL > AV_SAL
;
@XPLAN;
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 65 (2)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | VIEW | | 20000 | 253K| 65 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 20000 | 60000 | 65 (2)| 00:00:01 |
----------------------------------------------------------------------------
-- 인라인 뷰 안의 내용만 확인할 경우
EXPLAIN PLAN FOR
SELECT /*+ NO_MERGE */
OUTER.DEPT_NO,
OUTER.SAL,
OUTER.EMP_NO,
OUTER.PADDING,
(SELECT AVG(INNER.SAL)
FROM EMP
INNER WHERE INNER.DEPT_NO = OUTER.DEPT_NO) AV_SAL
FROM EMP OUTER
;
@XPLAN;
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20000 | 1406K| 65 (2)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| EMP | 3333 | 26664 | 65 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL | EMP | 20000 | 1406K| 65 (2)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("INNER"."DEPT_NO"=:B1)
DROP TABLE T1;
CREATE TABLE T1
AS
SELECT *
FROM ALL_OBJECTS
WHERE ROWNUM <= 3000
;
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME => 'T1',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT =>'FOR ALL COLUMNS SIZE 1');
END;
/
EXPLAIN PLAN FOR
WITH GENERATOR AS
(
SELECT /*+ INLINE */
ROWNUM ID
FROM T1
WHERE ROWNUM <= 1000
)
SELECT /*+ ORDERED USE_NL(V2) */
MOD(ROWNUM, 6),
ROWNUM,
ROWNUM,
RPAD('X', 60)
FROM GENERATOR V1,
GENERATOR V2
WHERE ROWNUM <= 20000
;
@XPLAN;
----------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20000 | 262 (1)| 00:00:04 |
|* 1 | COUNT STOPKEY | | | | |
| 2 | NESTED LOOPS | | 20000 | 262 (1)| 00:00:04 |
| 3 | VIEW | | 20 | 1 (0)| 00:00:01 |
|* 4 | COUNT STOPKEY | | | | |
| 5 | TABLE ACCESS FULL| T1 | 3000 | 13 (0)| 00:00:01 |
| 6 | VIEW | | 1000 | 13 (0)| 00:00:01 |
|* 7 | COUNT STOPKEY | | | | |
| 8 | TABLE ACCESS FULL| T1 | 3000 | 13 (0)| 00:00:01 |
----------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=20000)
4 - filter(ROWNUM<=1000)
7 - filter(ROWNUM<=1000)
DROP TABLE T1;
CREATE TABLE T1
AS
SELECT *
FROM ALL_OBJECTS
WHERE ROWNUM <= 3000
;
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME => 'T1',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT =>'FOR ALL COLUMNS SIZE 1');
END;
/
EXPLAIN PLAN FOR
WITH GENERATOR AS
(
SELECT /*+ MATERIALIZE */
ROWNUM ID
FROM T1
WHERE ROWNUM <= 1000
)
SELECT /*+ ORDERED USE_NL(V2) */
MOD(ROWNUM, 6),
ROWNUM,
ROWNUM,
RPAD('X', 60)
FROM GENERATOR V1,
GENERATOR V2
WHERE ROWNUM <= 20000
;
@XPLAN;
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20000 | | 2030 (1)| 00:00:25 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | | | | | |
|* 3 | COUNT STOPKEY | | | | | |
| 4 | TABLE ACCESS FULL | T1 | 3000 | | 13 (0)| 00:00:01 |
|* 5 | COUNT STOPKEY | | | | | |
| 6 | NESTED LOOPS | | 1000K| | 2017 (1)| 00:00:25 |
| 7 | VIEW | | 1000 | | 2 (0)| 00:00:01 |
| 8 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6602_EC10A807 | 1000 | 13000 | 2 (0)| 00:00:01 |
| 9 | VIEW | | 1000 | | 2 (0)| 00:00:01 |
| 10 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6602_EC10A807 | 1000 | 13000 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(ROWNUM<=1000)
5 - filter(ROWNUM<=20000)
DROP TABLE T;
CREATE TABLE T AS
SELECT MOD(LEVEL, 10) GUBN,
LEVEL VAL
FROM DUAL
CONNECT BY LEVEL <= 1000;
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME => 'T',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT =>'FOR ALL COLUMNS SIZE 1');
END;
/
EXPLAIN PLAN FOR
SELECT *
FROM (SELECT GUBN, SUM(VAL)
FROM T
GROUP BY GUBN) T_1,
T T_2
WHERE T_1.GUBN = T_2.GUBN
;
@XPLAN;
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 32000 | 8 (25)| 00:00:01 |
|* 1 | HASH JOIN | | 1000 | 32000 | 8 (25)| 00:00:01 |
| 2 | VIEW | | 10 | 260 | 4 (25)| 00:00:01 |
| 3 | HASH GROUP BY | | 10 | 60 | 4 (25)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T | 1000 | 6000 | 3 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL | T | 1000 | 6000 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T_1"."GUBN"="T_2"."GUBN")
EXPLAIN PLAN FOR
SELECT /*+ MERGE(T_1) */
*
FROM (SELECT GUBN, SUM(VAL)
FROM T
GROUP BY GUBN) T_1,
T T_2
WHERE T_1.GUBN = T_2.GUBN
;
@XPLAN;
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50000 | 585K| | 323 (4)| 00:00:04 |
| 1 | HASH GROUP BY | | 50000 | 585K| 3552K| 323 (4)| 00:00:04 |
|* 2 | HASH JOIN | | 100K| 1171K| | 8 (25)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 1000 | 6000 | | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T | 1000 | 6000 | | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("GUBN"="T_2"."GUBN")
EXPLAIN PLAN FOR
SELECT /*+ MERGE(T_1) MERGE(T_2) */
*
FROM (SELECT GUBN, SUM(VAL)
FROM T
GROUP BY GUBN) T_1,
(SELECT GUBN, SUM(VAL)
FROM T
GROUP BY GUBN) T_2,
T T_3
WHERE T_1.GUBN = T_2.GUBN
AND T_1.GUBN = T_3.GUBN
;
@XPLAN;
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 58000 | 12 (25)| 00:00:01 |
|* 1 | HASH JOIN | | 1000 | 58000 | 12 (25)| 00:00:01 |
|* 2 | HASH JOIN | | 10 | 520 | 9 (34)| 00:00:01 |
| 3 | VIEW | | 10 | 260 | 4 (25)| 00:00:01 |
| 4 | HASH GROUP BY | | 10 | 60 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL| T | 1000 | 6000 | 3 (0)| 00:00:01 |
| 6 | VIEW | | 10 | 260 | 4 (25)| 00:00:01 |
| 7 | HASH GROUP BY | | 10 | 60 | 4 (25)| 00:00:01 |
| 8 | TABLE ACCESS FULL| T | 1000 | 6000 | 3 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | T | 1000 | 6000 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T_1"."GUBN"="T_3"."GUBN")
2 - access("T_1"."GUBN"="T_2"."GUBN")
DROP TABLE T1;
DROP TABLE T2;
DROP TABLE T3;
CREATE TABLE T1 AS
SELECT ROWNUM - 1 ID1,
TRUNC((ROWNUM - 1) / 10) N1,
LPAD(ROWNUM, 10, '0') SMALL_VC,
RPAD('X', 100) PADDING
FROM ALL_OBJECTS
WHERE ROWNUM <= 5000;
ALTER TABLE T1 ADD CONSTRAINT T1_PK PRIMARY KEY(ID1);
CREATE TABLE T2 AS
SELECT TRUNC((ROWNUM - 1) / 5) ID1,
ROWNUM ID2,
LPAD(ROWNUM, 10, '0') SMALL_VC,
RPAD('X', 100) PADDING
FROM ALL_OBJECTS
WHERE ROWNUM <= 25000;
ALTER TABLE T2 ADD CONSTRAINT T2_PK PRIMARY KEY(ID1, ID2);
CREATE TABLE T3 AS
SELECT TRUNC((ROWNUM - 1) / 5) ID1,
ROWNUM ID2,
LPAD(ROWNUM, 10, '0') SMALL_VC,
RPAD('X', 100) PADDING
FROM ALL_OBJECTS
WHERE ROWNUM <= 25000;
ALTER TABLE T3 ADD CONSTRAINT T3_PK PRIMARY KEY(ID1, ID2);
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME =>'T1',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME =>'T2',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => USER,
TABNAME =>'T3',
CASCADE => TRUE,
ESTIMATE_PERCENT => NULL,
METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
END;
/
CREATE OR REPLACE VIEW V1 AS
SELECT T2.ID1,
T2.ID2,
T3.SMALL_VC,
T3.PADDING
FROM T2,
T3
WHERE T3.ID1 = T2.ID1
AND T3.ID2 = T2.ID2
;
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ NO_PUSH_PRED(V1) */
T1.*,
V1.*
FROM T1,
V1
WHERE V1.ID1(+) = T1.ID1
AND T1.N1 = 5
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('2hswhprr2pp84', NULL, 'ALLSTATS LAST'));
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
|* 1 | HASH JOIN OUTER | | 1 | 50 | 50 |00:00:00.30 | 25545 | 752K| 752K| 1083K (0)|
|* 2 | TABLE ACCESS FULL | T1 | 1 | 10 | 10 |00:00:00.01 | 91 | | | |
| 3 | VIEW | V1 | 1 | 25000 | 25000 |00:00:00.25 | 25454 | | | |
| 4 | NESTED LOOPS | | 1 | 25000 | 25000 |00:00:00.23 | 25454 | | | |
| 5 | TABLE ACCESS FULL| T3 | 1 | 25000 | 25000 |00:00:00.03 | 448 | | | |
|* 6 | INDEX UNIQUE SCAN| T2_PK | 25000 | 1 | 25000 |00:00:00.15 | 25006 | | | |
-------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("V1"."ID1"="T1"."ID1")
SELECT T1.*,
V1.*
FROM T1,
V1
WHERE V1.ID1(+) = T1.ID1
AND T1.N1 = 5
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('gh71wnftc6m85', NULL, 'ALLSTATS LAST'));
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 1 | NESTED LOOPS OUTER | | 1 | 50 | 50 |00:00:00.01 | 182 |
|* 2 | TABLE ACCESS FULL | T1 | 1 | 10 | 10 |00:00:00.01 | 95 |
| 3 | VIEW PUSHED PREDICATE | V1 | 10 | 1 | 50 |00:00:00.01 | 87 |
| 4 | NESTED LOOPS | | 10 | 1 | 50 |00:00:00.01 | 87 |
| 5 | TABLE ACCESS BY INDEX ROWID| T3 | 10 | 5 | 50 |00:00:00.01 | 32 |
|* 6 | INDEX RANGE SCAN | T3_PK | 10 | 5 | 50 |00:00:00.01 | 18 |
|* 7 | INDEX UNIQUE SCAN | T2_PK | 50 | 1 | 50 |00:00:00.01 | 55 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("T1"."N1"=5)
6 - access("T3"."ID1"="T1"."ID1")
7 - access("T2"."ID1"="T1"."ID1" AND "T3"."ID2"="T2"."ID2")
filter("T3"."ID1"="T2"."ID1")
- 강좌 URL : http://www.gurubee.net/lecture/4422
- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.