[SQLํŠœ๋‹]23.11.14_no_merge

๋ง๊ตฌ์”จยท2023๋…„ 11์›” 14์ผ
0

SQL ํŠœ๋‹

๋ชฉ๋ก ๋ณด๊ธฐ
4/9
post-thumbnail

โœ๏ธ ์ •๊ทœํ™”

๐Ÿ’ก ์ •๊ทœํ™”๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๋˜ ์ตœํ›„์˜ ์ˆ˜๋‹จ์œผ๋กœ ๋ฐ˜์ •๊ทœํ™” ํ•ฉ๋‹ˆ๋‹ค.

โœ… ์ •๊ทœํ™”๋ž€

์ค‘๋ณต๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ…Œ์ด๋ธ”์— ์—ฐ์†ํ•ด์„œ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก emp, dept๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ํ…Œ์ด๋ธ”๋กœ ๊ตฌ์„ฑํ–ˆ๋“ฏ์ด ํ…Œ์ด๋ธ”์„ ์„ฑ๊ฒฉ์— ๋งž์ถฐ์„œ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค. empํ…Œ์ด๋ธ”์—๋Š” ์‚ฌ์›์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ์žˆ๊ณ  dept์—๋Š” ๋ถ€์„œ์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ ์ค‘๋ณต์ด ์•ˆ๋˜๊ฒŒ ํ•˜๋ ค๊ณ  ๋ถ„๋ฆฌ๋ฅผ ํ–ˆ๋‹ค.

๋ถ„๋ฆฌ๋ฅผ ํ•˜๋‹ค๋ณด๋‹ˆ ์กฐ์ธ์ด ๋ถˆ๊ฐ€ํ”ผํ•ด์กŒ๋‹ค!

โœ”๏ธ select ๋ฌธ์˜ ์ˆ˜ํ–‰ ๋‹จ๊ณ„(๊ณผ์ •)
1. ํŒŒ์‹ฑ ----------> SQL์„ ๊ธฐ๊ณ„์–ด๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์‹คํ–‰๊ณ„ํš์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ
2. ์ต์ŠคํํŠธ
3. ํŒจ์น˜

select e.ename, d.loc
  from e, dept d
  where e.deptno = d.deptno;

โ“ ํ…Œ์ด๋ธ” 2๊ฐœ ์กฐ์ธ์„ ํ•˜๋ฉด ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์‹คํ–‰๊ณ„ํš์ด ๋ช‡๊ฐœ๊ฐ€ ๋ ๊นŒ?
1. ์กฐ์ธ ์ˆœ์„œ : 2๊ฐ€์ง€

* emp -> dept
* dept -> emp
  1. ์กฐ์ธ ๋ฐฉ๋ฒ• : 3๊ฐ€์ง€
* nested loop ์กฐ์ธ
* hash ์กฐ์ธ
* sort merge ์กฐ์ธ

โ“ ์ด 6๊ฐœ์˜ ์‹คํ–‰๊ณ„ํš์„ ์˜ตํ‹ฐ๋งˆ์ด์ €๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฐ€์žฅ ๋น„์šฉ์ด ์ ๊ฒŒ ๋“œ๋Š” ๊ณ„ํš์„ ์„ ํƒ

  • ํ…Œ์ด๋ธ”์ด 3๊ฐœ๋ฉด?
    ์กฐ์ธ ์ˆœ์„œ : 3 ! = 3*2*1=6
    ์กฐ์ธ ๋ฐฉ๋ฒ• : 3๊ฐœ
    ์ด 18๊ฐœ์˜ ์‹คํ–‰๊ณ„ํš์„ ์ƒ์„ฑ / ํ…Œ์ด๋ธ” 4๊ฐœ๋ฉด 72๊ฐœ, 5๊ฐœ๋ฉด 360๊ฐœ.....
    ์ด์ค‘์—์„œ ์ œ์ผ ์‹ผ(?) ์‹คํ–‰๊ณ„ํš ํ•˜๋‚˜๋งŒ ์„ ํƒํ•˜๋‹ˆ๊นŒ ํŒŒ์‹ฑ์ด ๋„ˆ๋ฌด ๋Š๋ฆฌ๋‹ค.

โžก๏ธ ๋„ˆ๋ฌด ์กฐ์ธ๋˜๋Š” SQL์ด ๋Š๋ฆฌ๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด, ๋ฐ˜์ •๊ทœํ™”๋ฅผ ๊ณ ๋ คํ•ด๋ณด์•„์•ผ ํ•œ๋‹ค.

โœ”๏ธ ์‹คํ–‰ ๊ณ„ํš์˜ ์ข…๋ฅ˜ 2๊ฐ€์ง€

1. ์˜ˆ์ƒ ์‹คํ–‰๊ณ„ํš

explain plan for 
select ename, sal
  from emp
  where ename='SCOTT';
  
select * from table(dbms_xplan.display);   

2. ์‹ค์ œ ์‹คํ–‰๊ณ„ํš
: buffers์˜ ๊ฐฏ์ˆ˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํŠœ๋‹ ์ „/ํ›„๋ฅผ ์ด๊ฒƒ์œผ๋กœ ๊ตฌ๋ถ„ํ•  ๊ฒƒ์ž„!

select /*+ gather_plan_statistics */ ename, sal
  from emp
  where ename='SCOTT';
  
SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));   

โœ… ๋ฐ˜์ •๊ทœํ™”๋ž€

๋‹ค๋ฅธ ์—”ํ‹ฐํ‹ฐ(ํ…Œ์ด๋ธ”)์— ์žˆ๋Š” ์†์„ฑ(์ปฌ๋Ÿผ)์„ ์ž์‹ ์˜ ๊ฒƒ์œผ๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
ex) emp ํ…Œ์ด๋ธ”์— loc์™€ dname์„ ํฌํ•จ์‹œํ‚ค๋Š” ๊ฒƒ์ด๋‹ค.

์‹ค์Šต1. ์•„๋ž˜์˜ 2๊ฐ€์ง€ ์ƒํ™ฉ์˜ ์‹ค์ œ ์‹คํ–‰๊ณ„ํš์„ ๋ณด๊ณ  ๋น„๊ตํ•˜๊ธฐ

1. ์ •๊ทœํ™” ํ–ˆ์„ ๋•Œ

select /*+ gather_plan_statistics */ e.ename, d.loc
  from emp e, dept d
  where e.deptno = d.deptno;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     14 |00:00:00.01 |       6 |       |       |          |
|*  1 |  HASH JOIN         |      |      1 |     14 |     14 |00:00:00.01 |       6 |   909K|   909K|  716K (0)|
|   2 |   TABLE ACCESS FULL| DEPT |      1 |      4 |      4 |00:00:00.01 |       3 |       |       |          |
|   3 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       3 |       |       |          |
----------------------------------------------------------------------------------------------------------------

2. ๋ฐ˜์ •๊ทœํ™” ํ–ˆ์„ ๋•Œ
2-1 emp ํ…Œ์ด๋ธ”์— loc์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€

alter table emp
 add loc varchar2(13);

2-2 emp ํ…Œ์ด๋ธ”์— ์ถ”๊ฐ€ํ•œ loc์ปฌ๋Ÿผ์˜ ๊ฐ’์„ ํ•ด๋‹น๋ถ€์„œ๋ฒˆํ˜ธ์˜ ๋ถ€์„œ์œ„์น˜๋กœ ๊ฐฑ์‹ 
merge๋ฌธ ์ฐธ๊ณ 

merge into emp e
using dept d
on (e.deptno=d.deptno)
when matched then 
  update set e.loc=d.loc;
 
-- ๋ฐ˜์ •๊ทœํ™”๋ฅผ ํ–ˆ์œผ๋ฏ€๋กœ ์กฐ์ธ์„ ์•ˆํ•ด๋„ ๋˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ฟผ๋ฆฌํ•ด๋„ ๋œ๋‹ค.
select /*+ gather_plan_statistics */ ename, loc
  from emp ;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     14 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       3 |
------------------------------------------------------------------------------------

โžก๏ธ ๋ฒ„ํผ์˜ ๊ฐฏ์ˆ˜๊ฐ€ 6๊ฐœ์—์„œ 3๊ฐœ๋กœ ์ค„์–ด๋“ค์—ˆ๋‹ค!

๋ฌธ์ œ (๋ฐ˜์ •๊ทœํ™”) emp ํ…Œ์ด๋ธ”์— dname์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  merge๋ฌธ์œผ๋กœ ํ•ด๋‹น ์‚ฌ์›์˜ ๋ถ€์„œ๋ช…์œผ๋กœ ๊ฐ’์„ ๊ฐฑ์‹ ํ•˜๊ธฐ

desc dept;
-- dname ์ถ”๊ฐ€ํ•˜๊ธฐ
alter table emp
 add dname varchar2(14);

-- merge๋ฌธ์œผ๋กœ ๊ฐ’ ๊ฐฑ์‹ 
merge into emp e
using dept d
on (e.deptno=d.deptno)
when matched then 
  update set e.dname=d.dname;

-- ๋ฐ˜์ •๊ทœํ™”๋ฅผ ํ–ˆ์œผ๋ฏ€๋กœ ์กฐ์ธ์„ ์•ˆํ•ด๋„ ๋˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ฟผ๋ฆฌํ•ด๋„ ๋œ๋‹ค.
select /*+ gather_plan_statistics */ ename, dname
  from emp ;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     14 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       3 |
------------------------------------------------------------------------------------

โœ๏ธ ์ธ๋ฑ์Šค ์„ค๊ณ„

๐Ÿ’ก primary์ œ์•ฝ๊ณผ unique ์ œ์•ฝ์„ ๊ฑธ๋ฉด ์ž๋™์œผ๋กœ ์ธ๋ฑ์Šค๊ฐ€ ์ƒ์„ฑ์ด๋œ๋‹ค.

alter table emp
  add constraint emp_empno_pk primary key(empno);

โœ”๏ธ ์ œ์•ฝ์ด ์ž˜ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ

select table_name, constraint_name
  from user_constraints
  where table_name='EMP';


โœ”๏ธ ์ธ๋ฑ์Šค๊ฐ€ ์ž˜ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ

select index_name, uniqueness
  from user_indexes
  where table_name='EMP';


โžก๏ธ ์ธ๋ฑ์Šค ์ด๋ฆ„์ด ์ œ์•ฝ ์ด๋ฆ„์œผ๋กœ ์ƒ์„ฑ์ด ๋œ๋‹ค.

โœ… ํšŒ์‚ฌ์— DB์˜ ์˜ค๋ธŒ์ ํŠธ ๋“ค์˜ ์ด๋ฆ„์„ ๊ฒฐ์ •ํ•  ๋•Œ ๊ทœ์น™์ด ์žˆ๋‹ค. ์ด ๊ทœ์น™๋“ค์„ ๋”ฐ๋ผ์•ผํ•จ

์˜ˆ) ํ…Œ์ด๋ธ”๋ช…์€ 8๊ธ€์ž๋ฅผ ๋„˜์œผ๋ฉด ์•ˆ๋˜๊ณ  ์ด๋ฆ„๋งˆ๋‹ค ์˜๋ฏธ๊ฐ€ ์žˆ์–ด์•ผํ•จ.
UEHBLDMT --->      UE        HB        LD        MT
                 ์ „์ž๊ธˆ์œต   ํšŒ์‚ฌ์•ฝ์–ด    ํšŒ์‚ฌ์•ฝ์–ด   ๋งˆ์Šคํ„ฐํ…Œ์ด๋ธ”

โœ… ์ธ๋ฑ์Šค ์ด๋ฆ„๋„ ๊ทœ์น™์ด ์žˆ๋‹ค!

UEHBLDIDX1 --->      UE        HB        LD        IDX๋ฒˆํ˜ธ 

๊ทธ๋Ÿฐ๋ฐ PK์™€ ์œ ๋‹ˆํฌ ์ œ์•ฝ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์ธ๋ฑ์Šค๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š”๋ฐ ์ธ๋ฑ์Šค ์ด๋ฆ„์ด ์ œ์•ฝ์ด๋ฆ„์œผ๋กœ ์ƒ์„ฑ๋˜๋‹ˆ๊นŒ ๋ฉ”ํƒ€ ๊ทœ์น™์— ๋งž์ง€ ์•Š์•„์„œ ๊ฐ์‚ฌ๋•Œ ์ง€์ ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. DBA๊ฐ€ ์ œ์•ฝ ์ด๋ฆ„๊ณผ ์ธ๋ฑ์Šค ์ด๋ฆ„์„ ์„œ๋กœ ๋‹ค๋ฅด๊ฒŒ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Œ!!

์ œ์•ฝ ์ด๋ฆ„๊ณผ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ์ธ๋ฑ์Šค ์ด๋ฆ„์„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•ด์„œ ๋งŒ๋“ค๊ธฐ

alter table emp
  add constraint emp_empno_pk primary key(empno);

alter table emp
  drop constraint emp_empno_pk;

alter table emp
  add constraint emp_empno_pk primary key(empno)
  using index (create unique index emp_idx1 on emp(empno));

๋ฌธ์ œ dept ํ…Œ์ด๋ธ”์— deptno์— primary key์— ์ œ์•ฝ์„ ๊ฑฐ๋Š”๋ฐ, ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ์ธ๋ฑ์Šค ์ด๋ฆ„์€ dept_idx1 ๋ผ๊ณ  ํ•ด์„œ ์ƒ์„ฑ๋˜๊ฒŒ ๋งŒ๋“ค๊ธฐ

alter table dept
  add constraint dept_deptno_pk primary key(deptno)
  using index (create unique index dept_idx1 on dept(deptno));
-- ์ œ์•ฝ์ด๋ฆ„ ํ™•์ธ
select table_name, constraint_name
from user_constraints
where table_name='DEPT';

# DEPT   DEPT_DEPTNO_PK

-- ์ธ๋ฑ์Šค ์ด๋ฆ„ ํ™•์ธ
select index_name, uniqueness
from user_indexes
where table_name='DEPT';

# DEPT_IDX1	  UNIQUE

โœ๏ธ ๋ทฐ ์‚ฌ์šฉ์‹œ ์žฅ์ ๊ณผ ๋‹จ์ 

โœ”๏ธ ์žฅ์ 

1. view ์‚ฌ์šฉ์‹œ ์žฅ์ ์€ SQL ์ฝ”๋“œ๊ฐ€ ์‹ฌํ”Œํ•ด์ง„๋‹ค.

-- salesman์ธ ์‚ฌ์›๋“ค๋งŒ ๋ชจ์•„ view๋ฅผ ์ƒ์„ฑ
create view emp_salesman
as
  select empno, ename, job, mgr, hiredate, sal, comm, deptno
    from emp
    where job='SALESMAN';

-- ๋ทฐ๋ฅผ ์‚ฌ์šฉ ํ–ˆ์„ ๋•Œ
select * 
 from emp_salesman
 where sal >= 1200;

-- ๋ทฐ๋ฅผ ์‚ฌ์šฉ ์•ˆํ–ˆ์„ ๋•Œ
select empno, ename, job, mgr, hiredate, sal, comm, deptno
  from emp
  where job = 'SALESMAN' and sal >= 1200;

๐Ÿšจ VEIW๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ์ฃผ์˜์‚ฌํ•ญ!
: ์ž˜๋ชป๋œ ์‹คํ–‰๊ณ„ํš์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ… ์•„๋ž˜์˜ ์กฐ์ธ๋ฌธ์žฅ์„ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰๊ณ„ํš์„ ํ™•์ธํ•ด๋ณด๊ธฐ

select /*+ gather_plan_statistics leading(d e) */ 
         e.empno, e.ename, e.job, e.mgr, e.sal, d.loc
  from emp_salesman e, dept d
  where e.deptno = d.deptno and e.sal >= 1500;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      2 |00:00:00.01 |       6 |       |       |          |
|*  1 |  HASH JOIN         |      |      1 |      2 |      2 |00:00:00.01 |       6 |   909K|   909K|  712K (0)|
|   2 |   TABLE ACCESS FULL| DEPT |      1 |      4 |      4 |00:00:00.01 |       3 |       |       |          |
|*  3 |   TABLE ACCESS FULL| EMP  |      1 |      2 |      2 |00:00:00.01 |       3 |       |       |          |
----------------------------------------------------------------------------------------------------------------

โžก๏ธ leading(d e)๋ผ๊ณ  ํžŒํŠธ๋ฅผ ์ฃผ๋ฉด dept ๋จผ์ € ๋“œ๋ผ์ด๋น™ ํ•˜๊ณ  view๋ฅผ ๋“œ๋ผ์ด๋น™ ํ•ด๋ผ ! ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ง€๊ธˆ ์‹คํ–‰๊ณ„ํš์—๋Š” emp_salesman ์ž์ฒด๊ฐ€ ์—†๊ณ  emp๋งŒ ๋ณด์ธ๋‹ค. ์™œ ์•ˆ๋ณด์ด๋ƒ๋ฉด ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ view๋ฅผ ํ•ด์ฒดํ•˜๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ์‹คํ–‰ํ–ˆ๋‹ค.

select /*+ gather_plan_statistics leading(d e) */ 
         e.empno, e.ename, e.job, e.mgr, e.sal, d.loc
  from emp e, dept d 
  where e.deptno = d.deptno and job = 'SALESMAN' and e.sal >= 1500;

๐Ÿ’ก ์ด๋ ‡๊ฒŒ ์ž˜๋ชป๋œ ์‹คํ–‰๊ณ„ํš์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ view๋ฅผ ํ•ด์ฒดํ•˜์ง€ ๋ง๋ผ๊ณ  ํžŒํŠธ๋ฅผ ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

select /*+ gather_plan_statistics no_merge(e) leading(d e) */ 
         e.empno, e.ename, e.job, e.mgr, e.sal, d.loc
  from emp_salesman e, dept d
  where e.deptno = d.deptno and e.sal >= 1500;

-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |              |      1 |        |      2 |00:00:00.01 |       6 |       |       |          |
|*  1 |  HASH JOIN          |              |      1 |      2 |      2 |00:00:00.01 |       6 |   909K|   909K|  721K (0)|
|   2 |   TABLE ACCESS FULL | DEPT         |      1 |      4 |      4 |00:00:00.01 |       3 |       |       |          |
|   3 |   VIEW              | EMP_SALESMAN |      1 |      2 |      2 |00:00:00.01 |       3 |       |       |          |
|*  4 |    TABLE ACCESS FULL| EMP          |      1 |      2 |      2 |00:00:00.01 |       3 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------

โžก๏ธ no_merge ํžŒํŠธ๋Š” ๋ทฐ๋ฅผ ํ•ด์ฒดํ•˜์ง€ ๋ง์•„๋ผ ๋ผ๋Š” ํžŒํŠธ์ด๋‹ค!

โœ๏ธ SQL ์‹คํ–‰ ํšจ์œจ์„ฑ

๐Ÿ’ก ํ‰์ƒ์‹œ์— DBA๋Š” DB์— ์„ฑ๋Šฅ์ด ๋Š๋ฆฐ์ง€ ํ™•์ธ์„ ํ•ด์•ผํ•œ๋‹ค. ํ™•์ธํ•  ๋•Œ ์ฃผ๋กœ Active session (๋Œ€๊ธฐํ•˜๋Š” ์„ธ์…˜)๋“ค์ด ๋ฌด์Šจ ์ด์œ ๋กœ ๋Œ€๊ธฐํ•˜๋Š”์ง€ ๊ทธ ๋Œ€๊ธฐ ์ด๋ฒคํŠธ๋ฅผ ํ™•์ธํ•ด์•ผํ•œ๋‹ค.
๊ทธ ๋Œ€๊ธฐ ์ด๋ฒคํŠธ ์ค‘์—์„œ ์•„๋ž˜์˜ ๋Œ€๊ธฐ ์ด๋ฒคํŠธ๊ฐ€ ์ถœํ˜„ํ•˜๋ฉด shared pool์˜ SQL์ด ๊ณต์œ ๋˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ฆ๊ฑฐ์ž…๋‹ˆ๋‹ค.

latch : shared pool
latch : libary cache

โžก๏ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : SQL์„ PL/SQL๋กœ ์ฝ”๋”ฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ๊ณ ํ•˜๊ฑฐ๋‚˜ PL/SQL ๋‚ด์— ๋ฆฌํ„ฐ๋Ÿด SQL ์ฝ”๋”ฉ์ด ์žˆ๋‹ค๋ฉด ๋ฐ”์ธ๋“œ ๋ณ€์ˆ˜๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ๋ฅผ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๊ถŒ๊ณ ํ•ด์•ผํ•œ๋‹ค.

์‹ค์Šต owi.zip ์„ ๋ชจ๋ฐ”ํ…€์œผ๋กœ /home/oracle๋ฐ‘์— ์˜ฌ๋ฆฌ๊ณ  unzip์œผ๋กœ ์••์ถ• ํ’€๊ธฐ

โœ”๏ธ ์••์ถ• ํ’€๊ธฐ

$ unzip owi.zip
SYS>  @install
Elapsed: 00:00:00.00
Input data file name(for default tablespace  ex. c:\owi\owi01.dbf): /home/oracle/owi01.dbf
Package body created.

Elapsed: 00:00:00.01
11:55:53 PROD > show user
USER is "OWI"

โœ”๏ธ ์•กํ‹ฐ๋ธŒ ์„ธ์…˜ ๋ณด๋Š” ์Šคํฌ๋ฆฝํŠธ

SET LINESIZE 200
SET PAGESIZE 1000

COLUMN username FORMAT A20
COLUMN event FORMAT A30
COLUMN wait_class FORMAT A15

SELECT NVL(s.username, '(oracle)') AS username,
      s.sid,
      s.serial#,
      sw.event,
      sw.wait_class,
      sw.wait_time,
      sw.seconds_in_wait,
      sw.state
FROM   v$session_wait sw,
      v$session s
WHERE  s.sid = sw.sid
ORDER BY sw.seconds_in_wait DESC;

โœ”๏ธ ์Šคํฌ๋ฆฝํŠธ ์ค€๋น„๊ฐ€ ๋˜๋ฉด ๋Œ๋ ค๋ณด๊ธฐ shared_pool_latch

OWI> @exec
11:58:27 PROD > accept event_name char prompt 'Event name to simulate: '
Event name to simulate: shared_pool_latch

11:59:03 PROD > accept session_num number default 10 prompt 'Session count [10]: '
Session count [10]: 10
11:59:06 PROD > accept expired_type number default 1 prompt 'Expired by time(1) or looping count(2) [1]: '
Expired by time(1) or looping count(2) [1]: 1
11:59:08 PROD > accept interval number default 30 prompt 'Execution internval(sec or count) [30]: '
Execution internval(sec or count) [30]: 60
11:59:13 PROD > accept enable_trace number default 0 prompt 'Enable_trace (1=TRUE, 0=FALSE) [0]: '
Enable_trace (1=TRUE, 0=FALSE) [0]: 1
11:59:18 PROD > ACCEPT exec_method NUMBER DEFAULT 0 prompt 'Exec method(0=Oracle Job, 1=Unix Shell) [0]: '
Exec method(0=Oracle Job, 1=Unix Shell) [0]: 0
11:59:23 PROD > accept init_on_creation number default 1 prompt 'Init data(1=TRUE, 0=FALSE) [1]: '
Init data(1=TRUE, 0=FALSE) [1]: 1

๋ฌธ์ œ ADDM ๋ ˆํฌํŠธ๋ฅผ ๋– ์„œ ํ˜„์žฌ db๊ฐ€ ๋Š๋ฆฐ ์ด์œ ์™€ ํ•ด๊ฒฐ์ฑ…์„ ์‚ดํŽด๋ณด๊ธฐ

OWI> exec dbms_workload_repository.create_snapshot;
OWI> @?/rdbms/admin/addmrpt.sql
Summary of Findings
-------------------
   Description                      Active Sessions      Recommendations
                                    Percent of Activity
   -------------------------------  -------------------  ---------------
1  PL/SQL Execution                 .27 | 42.86          1
2  Soft Parse                       .24 | 38.27          2
3  Hard Parse Due to Literal Usage  .11 | 17.15          1
4  Latch Free Waits                 .03 | 4.79           0
5  CPU Usage                        .02 | 3.49           1

Finding 3: Hard Parse Due to Literal Usage
Impact is .11 active sessions, 17.15% of total activity.
--------------------------------------------------------
SQL statements were not shared due to the usage of literals. This resulted in
additional hard parses which were consuming significant database time.

   Recommendation 1: Application Analysis
   Estimated benefit is .11 active sessions, 17.15% of total activity.
   -------------------------------------------------------------------
   Action
      Investigate application logic for possible use of bind variables instead
      of literals. โ˜… ๋ฆฌํ„ฐ๋Ÿด ๋ณ€์ˆ˜ ๋Œ€์‹  ๋ฐ”์ธ๋“œ ๋ณ€์ˆ˜๋ฅผ ์จ๋ผ.
   Action
      Alternatively, you may set the parameter "cursor_sharing" to "force".
      โ˜… cursor_sharing๋ฅผ force๋กœ ๋ฐ”๊ฟ”๋ผ
   Rationale
      At least 27 SQL statements with FORCE_MATCHING_SIGNATURE
      17109837705936771014 and PLAN_HASH_VALUE 3909286317 were found to be
      using literals. Look in V$SQL for examples of such SQL statements.

   Symptoms That Led to the Finding:
   ---------------------------------
      Hard parsing of SQL statements was consuming significant database time.
      Impact is .11 active sessions, 17.16% of total activity.
         Contention for latches related to the shared pool was consuming
         significant database time.
         Impact is .09 active sessions, 14.36% of total activity.
            Wait class "Concurrency" was consuming significant database time.
            Impact is .09 active sessions, 14.36% of total activity.

์ ์‹ฌ์‹œ๊ฐ„ ๋ฌธ์ œ cursor_sharing๋ฅผ force๋กœ ๋ฐ”๊พธ๊ธฐ

12:10:09 PROD > alter system set cursor_sharing=force
12:10:37 PROD > show parameter cursor_sharing

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
cursor_sharing                       string      FORCE

โœ๏ธ ์ปค์„œ ๊ณต์œ ๋ฅผ ์œ„ํ•œ SQL ์ž‘์„ฑ

๐Ÿ’ก Shared pool์—์„œ ๊ณต์œ ๊ฐ€ ๋˜๋Š” ๋˜‘๊ฐ™์€ SQL์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

  1. ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„
select ename, sal from emp where empno = 7788;
SELECT ENAME, SAL FROM EMP WHRER EMPNO = 7788;
  1. ๊ณต๋ฐฑ๊ณผ ๋“ค์—ฌ์“ฐ๊ธฐ๋„ ๊ตฌ๋ถ„
select ename, sal from emp where empno = 7788;
select    ename,      sal   from   emp  where empno = 7788;
  1. ๋ฆฌํ„ฐ๋Ÿด SQL์„ ๊ตฌ๋ถ„
    : ๊ฐ€๊ธ‰์  SQL์„ PL/SQL๋กœ ์ฝ”๋”ฉ์„ํ•˜๊ณ  ๋ฆฌํ„ฐ๋Ÿด SQL์€ ๋ฐ”์ธ๋“œ ๋ณ€์ˆ˜๋กœ ๋ณ€๊ฒฝํ•ด์„œ ์ฝ”๋”ฉ์„ ํ•˜๊ฒŒ๋” ํ•ด์•ผ latch : shared pool์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
select ename, sal from emp where empno = 7788;
select ename, sal from emp where empno = 7902;
  • sql๋ฌธ์žฅ
  • ์‹คํ–‰๊ณ„ํš
  • ํŒŒ์ŠคํŠธ๋ฆฌ
    ์ด๋ ‡๊ฒŒ 3๊ฐœ๊ฐ€ ํŒŒ์‹ฑ ๊ฒฐ๊ณผ๋ฌผ์ธ๋ฐ ์ด๊ฒƒ์„ shared pool์— ์˜ฌ๋ฆฐ๋‹ค.

โœ… ์†Œํ”„ํŠธ ํŒŒ์‹ฑ๊ณผ ํ•˜๋“œ ํŒŒ์‹ฑ์˜ ์ฐจ์ด?
์†Œํ”„ํŠธ ํŒŒ์‹ฑ์€ ์ˆ˜ํ–‰ํ•˜๋Š” SQL๊ณผ ๋˜‘๊ฐ™์€ SQL์„ ๊ณต์œ ํ’€์—์„œ ์ฐพ์•„์„œ ํŒŒ์‹ฑ๊ณผ์ •์„ ์ƒ๋žตํ•˜๋Š” ๊ฒƒ์ด๊ณ  ํ•˜๋“œํŒŒ์‹ฑ์€ ์ฐพ์ง€ ๋ชปํ•ด์„œ ๋‹ค์‹œ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

๐Ÿ“– 3์žฅ. ์˜ตํ‹ฐ๋งˆ์ด์ € ์†Œ๊ฐœ

๐Ÿ’ก ์˜ค๋ผํด ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ์–ด๋–ค ์—ญํ• ?
๐Ÿ’ก ์˜ค๋ผํด ์˜ตํ‹ฐ๋งˆ์ด์ €์ €๊ฐ€ ์‹คํ–‰๊ณ„ํš์„ ๋งŒ๋“œ๋Š” ๋‹จ๊ณ„

โœ๏ธ SQL๋ฌธ


โญ ์˜ค๋ผํด ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ๋Š” SGA, PGA๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

SQL๋ฌธ์˜ ์ฒ˜๋ฆฌ๊ณผ์ •

select empno, ename
 from emp
 where empn=7788;

1. parsing :

๊ตฌ๋ฌธ ๋ถ„์„ : SQL ๋ฌธ๋ฒ•์ด ์˜ค๋ฅ˜๊ฐ€ ์—†๋Š”์ง€ ๊ฒ€์‚ฌ
์˜๋ฏธ ํ™•์ธ : empํ…Œ์ด๋ธ”์—  db๊ฐ€ ์กด์žฌํ•˜๋Š”ํ…Œ์ด๋ธ”์ž„
๊ถŒํ•œ ํ™•์ธ : empํ…Œ์ด๋ธ”์„ select ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
โ˜… ์ด SQL์„ ์œ„ํ•ด PGA์˜์—ญ ๊ณต๊ฐ„ ํ™•๋ณด๋ฅผ ํ•œ๋‹ค.

โžก๏ธ ๋˜‘๊ฐ™์€ SQL์ด ๊ณต์œ ํ’€์— ์žˆ์œผ๋ฉด ๋ฐ”๋กœ ์‹คํ–‰(์†Œํ”„ํŠธํŒŒ์‹ฑ)ํ•˜๊ณ  ์—†์œผ๋ฉด ํŒŒ์‹ฑ์„ ํ•ด์„œ ๊ณต์œ ํ’€์— ์˜ฌ๋ฆฐ๋‹ค. (ํ•˜๋“œํŒŒ์‹ฑ) ์ด๋•Œ latch๋ฅผ ์žก๋Š”๋ฐ, latch๋Š” shared pool latch์ด๋‹ค. ์žก์•„์•ผ ํŒŒ์‹ฑํ•œ ๊ฒฐ๊ณผ๋ฌผ 3๊ฐ€์ง€๋ฅผ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
2. execute :

๋ฐ์ดํ„ฐ๋ฅผ buffer cache์—์„œ ์ฐพ๊ณ  ์—†์œผ๋ฉด datafile์—์„œ ์ฐพ์•„์„œ ๋ณต์‚ฌ๋ณธ์„ ๋ฒ„ํผ์บ์‹œ์— ์˜ฌ๋ฆฐ๋‹ค.

3. fetch :

์ฐพ์€ data๋ฅผ ์„œ๋ฒ„ํ”„๋กœ์„ธ์„œ๊ฐ€ ์œ ์ €ํ”„๋กœ์„ธ์„œ์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

โœ๏ธ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ํ•„์š”ํ•œ ์ด์œ 


๐Ÿ’ก ๊ณ„ํš์„ ๋„์ถœํ•˜๋Š” ๊ฒƒ์ด ์˜ตํ‹ฐ๋งˆ์ด์ €์ด๋‹ค. ์ธ๋ฑ์Šค ์Šค์บ”๊ณผ ํ’€ํ…Œ์ด๋ธ” ์Šค์บ” ์ค‘์— ๋” ๋น ๋ฅธ๊ฒƒ์„ ๊ฒฐ์ •ํ•˜๋Š”๊ฒƒ์ด ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ์—ญํ• ์ด๋‹ค!

select * from emp where job = 'MANAGER';

โžก๏ธ job์— ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด full table scan,index range scan ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ 2๊ฐœ์˜ ์‹คํ–‰๊ณ„ํš์ค‘์— ์–ด๋–ค๊ฒƒ์„ ์„ ํƒํ•˜๋ƒ๋ฉด, ๊ฐ€์žฅ ๋น„์šฉ์ด ์ ๊ฒŒ ๋“œ๋Š” ๊ฒƒ์„ ์„ ํƒํ•œ๋‹ค. ์—๋ฅผ๋“ค์–ด job์ด manager์ธ ์‚ฌ์›์ด ์ „์ฒด ์‚ฌ์›์ˆ˜์˜ 1๋ช…์ด๋‹ค ๋ผ๊ณ  ํ•œ๋‹ค๋ฉด full table scan๋ณด๋‹ค index range scan์ด ๋น„์šฉ์ด ์ ๊ฒŒ ๋“ค๊ณ , job์ด manager์ธ ์‚ฌ์›์ด 14๋ช…์ค‘์— 13๋ช…์ด๋‹ค ๋ผ๊ณ  ํ•˜๋ฉด ์ธ๋ฑ์Šค ์Šค์บ” ๋ณด๋‹ค ํ’€ํ…Œ์ด๋ธ” ์Šค์บ”์ด ๋น„์šฉ์ด ๋” ์ ๊ฒŒ ๋“ ๋‹ค!

job์ด manager์ธ ์‚ฌ์›์ด ๋ช‡๋ช…์žˆ๋Š”์ง€ ์•Œ์•„์•ผํ•˜๋Š”๋ฐ ๊ทธ๊ฒƒ์„ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ํ…Œ์ด๋ธ” ํ†ต๊ณ„์ •๋ณด๋ฅผ ๋ด…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ DBA๊ฐ€ ํ…Œ์ด๋ธ” ํ†ต๊ณ„์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•ด์ค˜์•ผ ํ•œ๋‹ค!!!

์‹ค์Šต1.

@demobld 
  1. ์œ„ ์Šคํฌ๋ฆฝํŠธ ๋Œ๋ฆฌ๊ณ  job์ด PRESIDNT ๊ฐ€ ์•„๋‹Œ ์‚ฌ์›๋“ค์€ ์ „๋ถ€ ์ง์—…์„ ๋งค๋‹ˆ์ €๋กœ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค.
16:24:30 PROD > update emp
16:24:35   2  set job='MANAGER'
16:24:43   3  where job!='PRESIDENT';
commit;
  1. job์— ์ต๋ฑ์Šค๋ฅผ ์ƒ์„ฑ
create index emp_job on emp(job);
  1. emp ํ…Œ์ด๋ธ”์˜ ํ…Œ์ด๋ธ” ํ†ต๊ณ„์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•œ๋‹ค.
exec dbms_stats.gather_table_stats('SCOTT', 'EMP');
  1. ์•„๋ž˜์˜ 2๊ฐœ์˜ SQL์„ ์‹คํ–‰๊ณ„ํš์„ ํ™•์ธํ•˜๊ณ  ์‹คํ–‰๊ณ„ํš์ด ์ฑ…์ฒ˜๋Ÿผ ์ •๋ง ๊ฐ๊ฐ ๋‚˜๋ฅด๊ฒŒ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธ
explian plan for
select * from emp where job='PRESIDENT';
select * from table(dbms_xplan.display); 

explian plan for
select * from emp where job='MANAGER';
select * from table(dbms_xplan.display); 
  • ์‹ค์ œ ์‹คํ–‰ ๊ณ„ํš
select /*+ gather_plan_statistics */ *
 from emp
 where job='MANAGER';

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     13 |00:00:00.01 |       3 |
|*  1 |  TABLE ACCESS FULL| EMP  |      1 |     13 |     13 |00:00:00.01 |       3 |
------------------------------------------------------------------------------------

select /*+ gather_plan_statistics */ *
 from emp
 where job='PRESIDENT';

 SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

์˜ค๋Š˜์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ œ emp ํ…Œ์ด๋ธ”์˜ ๊ฑด์ˆ˜๋ฅผ 10000๊ฑด ์ด์ƒ ๊ฐ•์ œ๋กœ ๋Š˜๋ฆฌ๊ณ , job์ด PRESIDENT๋Š” 1๋ช…๋งŒ ๋‘๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ „๋ถ€ MANAGER๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ. ๊ทธ๋ฆฌ๊ณ  ์œ„ ํ…Œ์ŠคํŠธ ๋‹ค์‹œ ํ•˜๊ธฐ

  1. emp ํ…Œ์ด๋ธ” ๊ฑด์ˆ˜๋ฅผ 10000๊ฑด์ด์ƒ ๋Š˜๋ฆฌ๊ธฐ
insert into emp
 select *  
  from emp;

PROD > select rowid from emp
        where rownum < 2;

ROWID
------------------
AAADM4AABAAAHcpAAA
  1. 1๊ฑด๋นผ๊ณ  ๋ชจ๋‘ MANAGER๋กœ ๋ณ€๊ฒฝ
update emp
 set job='MANAGER';

update emp
 set job='PRESIDENT'
 where rowid='AAADM4AABAAAHcpAAA';

commit; 

โžก๏ธ ์ด๋Ÿฐ ๊ทน๋‹จ์ ์ธ ๋ฐ์ดํ„ฐ์˜ ๊ฒฝ์šฐ๋Š” ๊ทธ๋ƒฅ ํ†ต๊ณ„์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋ฉด ์•ˆ๋˜๊ณ , ํžˆ์Šคํ† ๊ทธ๋žจ ํ†ต๊ณ„์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

--์•„๊นŒ ์ˆ˜์—…๋•Œ ๋ฐ”๊ฟ”๋†“์€ force ์›๋ž˜๋Œ€๋กœ ๋˜๋Œ๋ฆผ
alter system set cursor_sharing=exact;

-- ํ†ต๊ณ„์ •๋ณด ์ˆ˜์ง‘
exec dbms_stats.gather_table_stats('SCOTT','EMP', method_opt => 'for all columns size skewonly');
or
analyze table emp compute statistics for columns job;
  1. ์‹ค์ œ ์‹คํ–‰ ๊ณ„ํš
select /*+ gather_plan_statistics */ count(*) 
 from emp
 where job='MANAGER';

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

-------------------------------------------------------------------------------------------
| Id  | Operation             | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |         |      1 |        |      1 |00:00:00.01 |    1052 |
|   1 |  SORT AGGREGATE       |         |      1 |      1 |      1 |00:00:00.01 |    1052 |
|*  2 |   INDEX FAST FULL SCAN| EMP_JOB |      1 |  28671 |  28671 |00:00:00.06 |    1052 |
-------------------------------------------------------------------------------------------

select /*+ gather_plan_statistics */ count(*)
 from emp
 where job='PRESIDENT';

 SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
---------------------------------------------------------------------------------------
| Id  | Operation         | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |      1 |        |      1 |00:00:00.01 |      47 |
|   1 |  SORT AGGREGATE   |         |      1 |      1 |      1 |00:00:00.01 |      47 |
|*  2 |   INDEX RANGE SCAN| EMP_JOB |      1 |      1 |      1 |00:00:00.01 |      47 |
---------------------------------------------------------------------------------------

๋‹ค์‹œ์‹ค์Šต

  1. t table ์ƒ์„ฑ
create table t
           as
           select decode(rownum,1,1,99) ID,
                  all_objects.*
             from all_objects;
  1. ์ธ๋ฑ์Šค ์ƒ์„ฑ
create index t_idx on t (id);     
  1. ํ†ต๊ณ„์ •๋ณด ํ™•์ธ
set autotrace traceonly explain
select * from t where id= 1;

-------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows | Bytes | Cost (%CPU)| Time
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |    1 |   171 |     2   (0)| 00:00
:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |    1 |   171 |     2   (0)| 00:00
:01 |
|*  2 |   INDEX RANGE SCAN          | T_IDX |    1 |       |     1   (0)| 00:00
:01 |
-------------------------------------------------------------------------------
PROD > select * from t where id=99;

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 13447 |  2245K|    47   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    | 13447 |  2245K|    47   (0)| 00:00:01 |
--------------------------------------------------------------------------
profile
Slow and steady wins the race.

0๊ฐœ์˜ ๋Œ“๊ธ€