OracleãšPostgresã®äž¡æ¹ã§ã®SQLã¯ãšãªã®åŠçã«ã¯ãå€ãã®å
±éç¹ããããŸãã äœããã®æ¹æ³ã§ãè§£æãå®è¡ããã»ãã³ãã£ã¯ã¹ã確èªããå¿
èŠããããŸãïŒã¡ã¿æ
å ±ãå¿
èŠã§ããããããŒã¿ãã£ã¯ã·ã§ããªããŸãã¯ãã·ã¹ãã ã«ã¿ãã°ããšåŒã°ãããã©ããã¯é¢ä¿ãããŸããïŒã倿ãå®è¡ããæé©ãªå®è¡èšç»ãæ§ç¯ããŸãã³ã¹ããããããããäºåã«ã³ã³ãã€ã«ãããçµ±èšãå¿
èŠã§ãïŒã
ããããåŠçãžã®ã¢ãããŒãå
šäœãæ ¹æ¬çã«å€ãã1ã€ã®éèŠãªéãããããŸãã ãã¡ãããOracleã¯è§£æããããªã¯ãšã¹ãã®ã°ããŒãã«ãã£ãã·ã¥ã䜿çšããPostgresã¯ãªã¯ãšã¹ããããŒã«ã«ã«ä¿åããŸãã
ãã®èšäºã§ã¯ã1ã€ã®ã¢ãŒããã¯ãã£ãœãªã¥ãŒã·ã§ã³ã®éãã«ããã2ã€ã®DBMSã§ã¯ãšãªãåŠçãããšãããŸã£ããç°ãªãã€ããªãã®ãŒãè«ççã«ã©ã®ããã«ç¶ããã远跡ããããšããŸãã
äžèšã®äŸïŒOracle 11.2 XEããã³PostgreSQL 9.4ã®ããŒãžã§ã³ã§å®è¡ãããïŒã«ã¯ãã¯ãšãªã®å®è¡æéãå«ãŸããŠããŸãã çžå¯Ÿçãªå€ã«ã®ã¿é¢å¿ããããŸãããªã¯ãšã¹ãã«å€æŽãå ããåŸãå®è¡æéã倿Žãããåæ°ã§ãã ãã®å Žåã絶察æ°ã¯ãæ©åšãè² è·ãèšå®ã«å¿ããŠæ¡éãã«ç°ãªãå ŽåããããŸãã ãããã«åºã¥ãç¡æå³ãªçµè«ã®çç±ãäžããªãããã«ãèšäºã®ãã¹ãŠã®çµ¶å¯Ÿå€ã¯ãäž¡æ¹ã®ã·ã¹ãã ã§ã¯ãšãªã®1ã€ã10ç§ã«ãªãããã«ã¹ã±ãŒãªã³ã°ãããŸãã
ãªã©ã¯ã«
Oracleã¯ãè§£æããããªã¯ãšã¹ãã®ã€ã³ã¹ã¿ã³ã¹å
šäœïŒã©ã€ãã©ãªãã£ãã·ã¥ãã©ã€ãã©ãªãã£ãã·ã¥ïŒã«ã°ããŒãã«ãã£ãã·ã¥ã䜿çšããŸãã å®è¡ããããªã¯ãšã¹ãã®ãã©ã³ã¯ããã£ãã·ã¥å
ã«ããããšãä¿èšŒãããŸãããªã¯ãšã¹ãã¯ããã£ãã·ã¥ãããã§ã«æºåããããã©ã³ã§å®è¡ãããããæ°ãããã©ã³ãæ§ç¯ãããŠãã£ãã·ã¥ã«ä¿åãããŸãã
åçŽåãããäžè¬çãªã¯ãšãªå®è¡ã¹ããŒã ã¯ã次ã®ããã«è¡šãããšãã§ããŸãã
- ã¯ãšãªã®è§£æïŒSQLã³ãã³ãã®ã¹ãã«ãæ£ãããã©ããïŒã
- ã»ãã³ãã£ãã¯åæïŒãããã®ãªããžã§ã¯ããååšãããããã«ã¢ã¯ã»ã¹ã§ãããã©ããïŒã
- æºåãããèšç»ããã£ãã·ã¥ã«ããå Žåã¯ãããã䜿çšããŸãã ããã§ãªããã°-ããã«ã
- 倿ïŒãã¥ãŒãªã¹ãã£ãã¯ã«ãŒã«ã«åŸã£ãŠèŠæ±ãæžãæããïŒã
- æé©åïŒæå°ã³ã¹ãã®å®è£
èšç»ã®éžæïŒã
- éžæãããã©ã³ããã£ãã·ã¥ããŸãã
åããªã¯ãšã¹ããé£ç¶ããŠ2åç¹°ãè¿ããããšãåŠçæ¹æ³ãç°ãªããŸãã åããŠãããããå®å
šãªåæïŒããŒãè§£æïŒãè¡ãããŸã-æåã®æ®µèœããæåŸã®æ®µèœãŸã§ã 2åç®ã¯ãæ§æè§£æãšæå³è§£æã®éšåçãªè§£æã®ã¿ãå®è¡ãããŸãããã®åŸãæ¢è£œã®ãã©ã³ãæ€çŽ¢ããããã£ãã·ã¥ã§äœ¿çšãããŸããããã¯ããå¹ççã§ãã
ã°ããŒãã«ãã£ãã·ã¥ã®ååšã¯ããã®äžã®ãšã³ããªã®æ°ãæå°éã«æããããã«ããã·ã¥ãããŸãã 1ã€ã®çç±ã¯ãã1åéãã®ããªã¯ãšã¹ãã®å€§ããªã¹ããªãŒã ãæçšãªãã©ã³ããã£ãã·ã¥ããæŒãåºãããšãã§ããäžæ¹ã§ããããã®ãªã¯ãšã¹ãèªäœã¯æ±ºããŠç¹°ãè¿ãããªãããã§ãã ããããæãéèŠãªããšã¯ã䞊åããã»ã¹ãå
±æãã£ãã·ã¥ã«ã¢ã¯ã»ã¹ããŠãããããããã¯ã§ä¿è·ããå¿
èŠããããæžã蟌ã¿ãããã«ããã¯ã«ãªãå¯èœæ§ãããããšã§ãã
å®éãå€ãã®è§£æãè¡ãããã»ã¹ã¯ãã€ã³ã¹ã¿ã³ã¹å
šäœã®åé¡ã«ãªããŸãã æ¬¡ã®äŸã§ãã®ç¶æ³ãèæ
®ããŠãã ããã
create table t(
id number primary key,
n number not null
);
insert into t(id, n)
select level, 1
from dual
connect by rownum <= 100000;
exec dbms_stats.gather_table_stats(user,'T');
alter session set statistics_level=all;
ããã§ãããŒãã«ãäœæããããã«10äžè¡ãæ¿å
¥ãïŒãrowid <= Nã«ãããã¥ã¢ã«æ¥ç¶ãããã³ã³ã¹ãã©ã¯ãã¯ãNè¡ã®éžæãçæããã€ãã£ãªã ã§ãïŒãçµ±èšãåéããŸãã
以äžã®PL / SQLã³ãŒããå®è¡ããŠã¿ãŸããããããã¯ãåçã«çæãããæŽæ°ã¯ãšãªã䜿çšããŠãããŒãã«ãã«ãŒãã§1è¡ãã€æŽæ°ããŸãïŒãããããã®äŸã¯éåžžã«æéãããããŸãããå®éã«ã¯ããã§ã¯ãããŸããïŒïŒ
begin
for i in (select id from t) loop
execute immediate 'update t set n = n + 1 where id = '||i.id;
end loop;
commit;
end;
/
ãã¬ãŒã¹ããå Žåãããã«ãããŸãã
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 100003 92.63 95.40 0 2837 0 0
Execute 100003 13.57 14.29 0 200002 102225 100000
Fetch 1002 0.87 0.75 0 10173 0 100000
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 201008 107.08 110.46 0 213012 102225 200000
Misses in library cache during parse: 100001
ã³ãŒãã®ãããã¯ããéå§ããããã¹ãŠã®SQLã¯ãšãªã«é¢ããæ
å ±ãããã«ç€ºããŸãã çµéåã¯åèšçµéæéïŒCPUãšããŸããŸãªæåŸ
å€ã§æ§æãããŸãïŒã瀺ããè§£æãå®è¡ããã§ããã®è¡ã¯ãã¯ãšãªçµæã®è§£æãå®è¡ãåä¿¡ã®æ®µéã«å¯Ÿå¿ããŸãã ã芧ã®ãšãããã¡ã€ã³ã®æéïŒ110åã®ãã¡95ç§ãçµéåïŒã¯ãåãã¿ã€ãã®ãªã¯ãšã¹ã10äžïŒã«ãŠã³ãåïŒã®è§£æãšãã®1åéãã®ãã©ã³ã®ãã£ãã·ã¥ãžã®æå
¥ã«è²»ããããŸããã è€æ°ã®åæ§ã®ããã»ã¹ãåæã«éå§ãããšããã©ããïŒå
±æããŒã«ãããã©ããïŒè¡ãã£ãã·ã¥ãªããžã§ã¯ããïŒããŒãžã§ã³ããšã«ååãå€ããïŒãªã©ã®æåŸ
ãçŸãå§ããã©ã€ãã©ãªãã£ãã·ã¥ãžã®ã¢ã¯ã»ã¹ã®ç«¶åã瀺ããŸãã
ãããé²ãã«ã¯ãOracleã§ãã€ã³ã倿°ã䜿çšããã®ãäžè¬çã§ãã ããšãã°ã次ã®ããã«ïŒ
begin
for i in (select id from t) loop
execute immediate 'update t set n = n + 1 where id = :A' using i.id;
end loop;
commit;
end;
/
ãŸãã¯ãPL / SQLã倿°ãããŒã¿ããŒã¹ãã€ã³ãã£ã³ã°å€æ°ã«èªåçã«å€æãããããåçSQLã䜿çšããã«ã·ã³ãã«ã«ãªããŸãã
begin
for i in (select id from t) loop
update t set n = n + 1 where id = i.id;
end loop;
commit;
end;
/
ãã®å Žåããã¬ãŒã¹ã¯æ¬¡ã®ããã«è¡šç€ºãããŸãã
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 3 0.02 0.03 0 297 0 0
Execute 100002 9.08 9.28 0 201694 102315 100000
Fetch 1001 0.77 0.68 0 10173 0 100000
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101006 9.87 10.00 0 212164 102315 200000
è§£ææéã¯æå°éã«ççž®ãããŸãããDBMSã®æŽæ°èŠæ±ã¯ãã¹ãŠåãã«ãªããŸããã ãã¢ã€ãã³ãã£ãã£ããã€ãŸãå®éã«ã¯ãã£ãã·ã¥ã®ããŒã¯ã2ã€ã®å€ã«ãã£ãŠæ±ºå®ãããŸãã
- sql_id-èŠæ±ããã¹ãã®ããã·ã¥ã³ãŒãïŒã€ãŸããä»»æã®æåãç°ãªãèŠæ±ã¯æ¢ã«ç°ãªãèŠæ±ã§ãïŒ
- child_number-å°ãªããšãæ§æçã«åäžã®ã¯ãšãªïŒåãsql_idã䜿çšïŒãæå³çã«ç°ãªãå¯èœæ§ããããç°ãªããã©ã³ãæããªããã°ãªããªããšããäºå®ã«ãã£ãŠã远å ã®å¿
èŠæ§ãçããŸãã
ãããã£ãŠãæŽæ°ã¯ãšãªã¯1åã ãè§£æãããŸãïŒcountåã®3çªã¯PL / SQLãããã¯ã®è§£æãforå¥ã®selectã¯ãšãªãã«ãŒãã®æ¬äœã®updateã¯ãšãªã«å¯Ÿå¿ããŸãïŒã 圌ã®èšç»ã¯ãã£ãã·ã¥ããããã¹ãŠãæ¯èŒçè¿
éã«æ©èœããŸãã
ïŒãªããçžå¯Ÿçããªã®ã§ããããïŒæ£ããæ¹æ³ã¯ã1ã€ã®ã³ãã³ããupdate t set n = n + 1ãã§æŽæ°ããããšã§ããããã¯1æ¡é«éã«å®è¡ãããŸããïŒ
ãã ãã倿°ã®å€ãèæ
®ããã«æ§ç¯ããããäžè¬çãªãã¯ãšãªãã©ã³ã¯ãåçã«åæ£ãããããŒã¿ã«ã®ã¿é©ããŠããŸãã
ããŒãã«ã倿ŽããŠã¿ãŸãããã0.1ïŒ
ã®è¡ã§ã¯ãYããæ®ãã®99.9ïŒ
ã§ã¯ãNãã«çãããã©ã°ãã£ãŒã«ãã远å ããŠã€ã³ããã¯ã¹ãäœæããŸãã
alter table t add (
flag char(1) check (flag in ('Y','N'))
);
update t
set flag = case when mod(id,1000)=0 then 'Y' else 'N' end;
create index t_flag on t(flag);
ãªããã£ãã€ã¶ããã©ã°ãã£ãŒã«ãã®ããŒã¿ã®äžåäžæ§ãèæ
®ããããã«ã¯ããã®ãã£ãŒã«ãã®ãã¹ãã°ã©ã ãåéããå¿
èŠããããŸãã ããšãã°ã次ã®ããã«ïŒ
exec dbms_stats.gather_table_stats(user,'T',method_opt=>'for columns flag size 2');
è峿·±ãããšã«ãexplain planã³ãã³ãïŒãã®çµæã¯dbms_xplan.display颿°ã䜿çšããŠå©çšå¯èœïŒã¯ããªããã£ãã€ã¶ãŒãããŒãã«ã®ååãåãåãããšãæåŸ
ãããã®ããã«ãåäžæ§ã®ä»®å®ããæ§ç¯ããããã©ã³ãåŒãç¶ã衚瀺ããŸãã
explain plan for select * from t where flag = :f;
select * from table(dbms_xplan.display);
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50000 | 488K| 76 (2)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 50000 | 488K| 76 (2)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("FLAG"=:F)
ããã¯ãæŠããŠãOracleã®EXPLAIN PLANã³ãã³ãã䜿çšã§ããªãããšãæå³ããŸãã 倿°ã®å€ããã®åãèæ
®ãããã倿°ã«ãã£ãŠçæããããã©ã³ã¯ãã£ãã·ã¥ã«å
¥ããããããããªãæ¹æ³ã§ã䜿çšãããŸããã
å®éãã¯ãšãªãå®è¡ãããšãOracleã¯ãã€ã³ãã£ã³ã°å€æ°ã®å€ããèŠããïŒãããããã€ã³ãããŒã¯ããšåŒã³ãŸãïŒããããã®å€ã«åºã¥ããŠãã©ã³ãæ§ç¯ããŸãã èŠæ±ãæ¢ã«å®è¡ã®ããã«éä¿¡ãããŠè§£æãããŠããå Žåããã£ãã·ã¥ã§å®éã®ãã©ã³ãçŽæ¥èª¿ã¹ãå¿
èŠããããŸãã ãããè¡ãã«ã¯ãdbms_xplan.display_cursor颿°ã䜿çšããŸãã äŸã§æå®ããããã©ã¡ãŒã¿ãŒã䜿çšãããšãæåŸã«å®è¡ããããªã¯ãšã¹ãã®ãã©ã³ãšãã€ã³ãã£ã³ã°å€æ°ã«é¢ããæ
å ±ã衚瀺ãããŸãã
var f char(1)
exec :f := 'Y'
select * from t where flag = :f;
...
100 rows selected.
select * from table(dbms_xplan.display_cursor(format=>'typical +peeked_binds'));
SQL_ID 6pncxxhknwgqc, child number 0
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 135 | 1350 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_FLAG | 135 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Peeked Binds (identified by position):
--------------------------------------
1 - :F (CHAR(30), CSID=873): 'Y'
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("FLAG"=:F)
ããã§ããªããã£ãã€ã¶ãŒã倿°ã®å€ïŒããŒã¯ãã€ã³ãã»ã¯ã·ã§ã³ïŒãèæ
®ããè¡æ°ãé©åã«æšå®ãïŒ135ããšã©ãŒã¯çµæã«åœ±é¿ããŸããïŒãã€ã³ããã¯ã¹ã«ããã¢ã¯ã»ã¹ãéžæããããšãæããã§ãã
åé¡ã¯ãçµã¿èŸŒã¿ã®ããã©ã€ããŒãããã©ã³ããã£ãã·ã¥ã«ç§»åãã倿°ã®å€ãèæ
®ããã«åããªã¯ãšã¹ãã«åå©çšãããããšã§ãã ããã¯åžžã«è¯ããšã¯éããŸããããã®äŸã§ã¯ãã€ã³ããã¯ã¹ã¢ã¯ã»ã¹ã¯ãNãã®å€ã«å¯ŸããŠéåžžã«éå¹ççã§ãã åŸæ¥ã解決çã¯ãã¯ãšãªããã¹ãã«ãªãã©ã«ã貌ãä»ããåçSQLã䜿çšããããšã§ãããã解決çã¯å€±æããŸãããäžèšã®æ¬ ç¹ã«å ããŠããã®ã¢ãããŒãã¯SQLã€ã³ãžã§ã¯ã·ã§ã³ã®å¯èœæ§ãããããå±éºã§ãã ãã®ããïŒããŒãžã§ã³11g以éïŒãOracleã¯ãã€ã³ãã£ã³ã°å€æ°ã®å€ã«ææãªã¯ãšãªãèŠã€ããŠåŠçããããšãã§ããŸãïŒããããé©å¿ã«ãŒãœã«å
±æããšåŒã³ãŸãïŒã ãªã¯ãšã¹ããå®è¡ãããšãããã§ã«ãã£ãã·ã¥ã«ãããã©ã³ã䜿çšãããŸãããå®éã«æ¶è²»ããããªãœãŒã¹ã¯è¿œè·¡ããã以åã®å®è¡ã®çµ±èšãšæ¯èŒãããŸãã
ãªã¯ãšã¹ãã«å¿ããŠãã©ã€ãã©ãªãã£ãã·ã¥ããã®æ
å ±ã®äžéšãèŠãŠã¿ãŸãããã
select child_number, is_bind_sensitive, is_bind_aware, executions, buffer_gets from v$sql where sql_id='6pncxxhknwgqc';
CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE EXECUTIONS BUFFER_GETS
------------ ----------------- ------------- ---------- -----------
0 Y N 1 128
èŠæ±ã¯ããã€ã³ãäŸåãšããŠããŒã¯ãããŸãã Buffer_gets-èªã¿åãããããŒã¿ãããã¯ã®æ°ã
ã¯ãšãªãä»ã®å€ã䜿çšããŠå®è¡ãããããšãæªãå Žåãæ¬¡ã«å®è¡ããããšãã«ãç°ãªããã©ã³ãå¿
èŠã§ãããšããŒã¯ãããŸãïŒãã€ã³ã察å¿ïŒã
ç°ãªããã©ã°ãã£ãŒã«ãå€ã§åããªã¯ãšã¹ããå®è¡ããŠã¿ãŸãããã
exec :f := 'N'
select * from t where flag = :f;
...
99900 rows selected.
ãã£ãã·ã¥ããã®ãã©ã³ã§ãªã¯ãšã¹ããå®è¡ãããããšã確èªããåæã«ããã©ã³ã®æåŸ
å€ã ãã§ãªãå®éã®å€ãåºåããå¯èœæ§ã瀺ããŸãïŒãã®ãããstatistics_levelãã©ã¡ãŒã¿ãŒãæåã«èšå®ãããŸããïŒã
select * from table(dbms_xplan.display_cursor(format=>'allstats last'));
SQL_ID 6pncxxhknwgqc, child number 0
-----------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 99900 | 41368 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 135 | 99900 | 41368 |
|* 2 | INDEX RANGE SCAN | T_FLAG | 1 | 135 | 99900 | 6842 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("FLAG"=:F)
äºæ³ãããè¡æ°ïŒ135ïŒãšå®éã®è¡ïŒ99900ïŒã«ã¯ççŸããããŸãã ããã«ãå®è¡ããããã«ã¯ãååïŒbuffer_getsåïŒãããã¯ããã«å€ãã®ããŒã¿ãèªã¿åãå¿
èŠããã£ãããšã¯æããã§ãã
select child_number, is_bind_sensitive, is_bind_aware, executions, buffer_gets from v$sql where sql_id='6pncxxhknwgqc';
CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE EXECUTIONS BUFFER_GETS
------------ ----------------- ------------- ---------- -----------
0 Y N 2 41496
ãªã¯ãšã¹ããå床å®è¡ããŸãã
select * from t where flag = :f;
...
99900 rows selected.
ããã§ããã€ã³ã倿°ã®æ°ããå€çšã«æ§ç¯ãããæ°ãããã©ã³ã䜿çšãããŸãïŒå€æŽãããåçªå·ãšããŒã¯ããããã€ã³ãã»ã¯ã·ã§ã³ã«æ³šæããŠãã ããïŒã
select * from table(dbms_xplan.display_cursor(format=>'typical +peeked_binds'));
SQL_ID 6pncxxhknwgqc, child number 1
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 77 (100)| |
|* 1 | TABLE ACCESS FULL| T | 99856 | 975K| 77 (3)| 00:00:01 |
--------------------------------------------------------------------------
Peeked Binds (identified by position):
--------------------------------------
1 - :F (CHAR(30), CSID=873): 'N'
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("FLAG"=:F)
ä»åããªããã£ãã€ã¶ãŒã¯è¡æ°ïŒ99856ãããããªãšã©ãŒã®ããŒãžã³ïŒãæ£ããæšå®ããå
šè¡šã¹ãã£ã³ãéžæããŸããã ãŸããã©ã€ãã©ãªãã£ãã·ã¥ã«ã¯ãåããªã¯ãšã¹ãã«å¯Ÿãã2ã€ã®ããŒãžã§ã³ã®ãã©ã³ããããŸãã
select child_number, is_bind_sensitive, is_bind_aware, executions, buffer_gets from v$sql where sql_id='6pncxxhknwgqc';
CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE EXECUTIONS BUFFER_GETS
------------ ----------------- ------------- ---------- -----------
0 Y N 2 41496
1 Y Y 1 6922
ãã£ãã·ã¥å
ã®ãã©ã³ã®æ°ãæå°éã«æããããããªããã£ãã€ã¶ãŒã¯1ã€ã®ãªã¯ãšã¹ãã«å¯ŸããŠç°ãªããã©ã³ã䜿çšãããã©ãããæ±ºå®ããåã«ãã€ãŸããããŸãã ããã¯ãäºåã«ãªããã£ãã€ã¶ãŒã«æåã§ãã³ããäžããããšã§åé¿ã§ããããšã«æ³šæããŠãã ããã
ãã¹ãã°ã¬ã¹
Postgresã«ã¯ãè§£æããããªã¯ãšã¹ãã®ã°ããŒãã«ãã£ãã·ã¥ã¯ãããŸããã ããã«ãç¹å¥ãªåªåãè¡ãããªãå Žåããªã¯ãšã¹ãã¯ããã»ã¹ã¡ã¢ãªã«ããŒã«ã«ã«ä¿åãããŸããã
ç¹ã«ãåããªã¯ãšã¹ããç¹°ãè¿ããšãæ¯åå®å
šã«éã¢ã»ã³ãã«ãããŸãã ãã¡ããããã®æ¹æ³ã§èšè¿°ãããããã»ã¹ã¯æé©ã«åäœããŸããããå°ãªããšãä»ã®ããã»ã¹ã«çŽæ¥åœ±é¿ãäžããããšã¯ãããŸããã
äŸãèããŠã¿ãŸãããïŒ
create table t(
id serial primary key,
n numeric not null
);
insert into t(n)
select 1 from generate_series(1,100000);
analyze t;
次ã®PL / pgSQLã³ãŒããå®è¡ããŸãã
\timing on
do $$
declare
i record;
begin
for i in (select id from t) loop
execute 'update t set n = n + 1 where id = '||i.id;
end loop;
end;
$$ language plpgsql;
DO
Time: 36164,377 ms
è§£æã®çµæãä¿åããã«ã¯ãã¯ãšãªãæºåããå¿
èŠããããŸãããã®å Žåã«ã®ã¿ãä¿åããã¯ãšãªãåå©çšã§ããŸãã
prepare u(integer) as update t set n = n + 1 where id = $1;
execute u(1);
execute u(2);
...
execute u(100000);
ããã¯ãæåã®äŸã®ããã«ãexecuteã䜿çšããã«PL / pgSQLãããã¯ã§SQLã³ãã³ããåŒã³åºããå Žåã«èµ·ããããšã§ãã ç§ãã¡ã®å Žåãããã«ãã3.5åã®é床åäžãåŸãããŸãã
do $$
declare
i record;
begin
for i in (select id from t) loop
update t set n = n + 1 where id = i.id;
end loop;
end;
$$ language plpgsql;
DO
Time: 10000,000 ms
ïŒãããŠãæ£ãããªãã·ã§ã³â 1ã€ã®SQLã³ãã³ãâã¯3åéãå®è¡ãããŸããïŒ
äžè¬çãªãªã¯ãšã¹ãè§£æã¹ããŒã ã¯ãæ¬¡ã®æé ã§æ§æãããŸãã
- è§£æ
- ã»ãã³ãã£ãã¯åæã
- æžãæããèŠæ±ããïŒã·ã¹ãã ãšãŠãŒã¶ãŒã®äž¡æ¹ã®èŠåã«åŸã£ãŠïŒã
- æé©åã
èŠæ±ãæºåãããšããããã¯åæãããæžãæããããŸãã æé©åã¯å®è¡æã«æ¹ããŠå®è¡ãããŸãããããã£ãŠããã€ã³ãã£ã³ã°å€æ°ã®åå€ã«å¯ŸããŠãç¬èªã®ããã©ã€ããŒãããã©ã³ãæ§ç¯ãããŸãã
äžåäžãªããŒã¿ååžã®äŸãèããŠã¿ãŸãããïŒæå倿°ã®ä»£ããã«ããŒã«åã䜿çšã§ããŸãïŒïŒ
alter table t add column
flag boolean;
update t
set flag = mod(id,1000)=0;
create index on t(flag);
ããŒãã«ã®åææã«ãå¿
èŠãªãã¹ãã°ã©ã ãèªåçã«äœæãããŸãã
analyze t;
ãªã¯ãšã¹ããæºåããŸãã
prepare s1(boolean) as select * from t where flag = $1;
ãã©ã°ã®çã®å€ã«å¯ŸããŠã©ã®å®è¡ãã©ã³ãéžæããããã調ã¹ãã«ã¯ãexplainã³ãã³ãã䜿çšããå¿
èŠããããŸãã Postgresã§ã¯ããã€ã³ã倿°ã®æå³ãšã¿ã€ããèªèããŠãããã³ãã³ããå®è¡ããããã©ã³ãæ£ç¢ºã«ç€ºããŠããŸãã
explain execute s1(true);
QUERY PLAN
------------------------------------------------------------------------
Index Scan using t_flag_idx on t (cost=0.29..14.31 rows=110 width=10)
Index Cond: (flag = true)
Filter: flag
ãªããã£ãã€ã¶ãŒã¯110è¡ãéžæããããšãæåŸ
ãïŒãããããããªèª€å·®ããããŸãïŒãã€ã³ããã¯ã¹ã¢ã¯ã»ã¹ã䜿çšããŸãã
ãŸããexplainã³ãã³ãã¯ããã©ã³ãäœæã§ããã ãã§ãªããã³ãã³ããå®è¡ããŠãã«ãŒãã£ããªãã£ã®æåŸ
å€ãšçŸåšå€ã®äž¡æ¹ãããã«ååŸã§ããããã䟿å©ã§ãã å¥ã®ãã©ã°å€ã§ããã瀺ããŸãã
explain analyze execute s1(false);
QUERY PLAN
------------------------------------------------------------------------------------------------------
Seq Scan on t (cost=0.00..2958.00 rows=99890 width=10) (actual time=0.043..265.272 rows=99900 loops=1)
Filter: (NOT flag)
Rows Removed by Filter: 100
Execution time: 385.455 ms
ãã®å Žåããªããã£ãã€ã¶ãŒã¯99890è¡ïŒå®éã«ã¯99900ïŒãååŸããããšãæåŸ
ããããŒãã«ã®å®å
šãªèªã¿åããé©åã«éžæããŸãã
ããã«ãããOracleãçŽé¢ããŠããåé¡ãšå察ã®åé¡ãçºçããŸãããã©ã³ããã€ã³ãã£ã³ã°å€æ°ã®å€ã«äŸåããŠããªãå Žåã¯ã©ããªããŸããïŒ ãã®å Žåãæ¯åãªã¯ãšã¹ããæé©åããªãããšãæçã§ãã
å®éãPostgresã¯ããã©ã€ããŒããèšç»ãããäžè¬ãèšç»ïŒäžè¬èšç»ïŒã«ç§»è¡ããæ¹æ³ãç¥ã£ãŠããŸãããããã«ã¯å®è¡ããŸããã ãªã¯ãšã¹ãã¯ãããã®å Žåã§ãæåã®5åæé©åããããã®ã³ã¹ãïŒãªããã£ãã€ã¶ãŒã«ããïŒããã©ã€ããŒããã©ã³ã®å¹³åã³ã¹ããè¶
ããªãå Žåãäžè¬ãã©ã³ãåªå
ãããŸãã ããã§ã®5çªã¯äžçš®ã®åŠ¥åã§ããå°ããªå€ã¯ãã€ã³ãã£ã³ã°å€æ°ã®ç°ãªãå€ã®å€ã«é¢ããååãªçµ±èšãæäŸããã倧ããªå€ã¯æé©åèªäœãç¡å¹ã«ããŸãã
ããŒã¿ã®åäžãªååžã䜿çšããäŸã䜿çšããŠããã®ã¡ã«ããºã ãæ€èšããŠãã ããã
prepare s2(integer) as select * from t where id = $1;
explain execute s2(1);
QUERY PLAN
-----------------------------------------------------------------
Index Scan using t_pkey on t (cost=0.42..8.44 rows=1 width=10)
Index Cond: (id = 1)
ããã¯ãã©ã€ããŒããã©ã³ã§ããããã€ã³ããã¯ã¹æ¡ä»¶ïŒïŒid = 1ïŒããšããæ¡ä»¶ã§ç¢ºèªã§ããŸããç¹å®ã®çªå·ãããã«ç€ºãããŠããŸãã
ãã ãã倿°ã®ä»»æã®å€ã䜿çšããŠExplainãåŒã³åºãããã¯ãšãªãããã«4åå®è¡ããå Žåã¯ãäžè¬çãªãã©ã³ã«åãæ¿ããŸãã
execute s2(2);
...
execute s2(3);
...
execute s2(4);
...
execute s2(5);
...
explain execute s2(6);
QUERY PLAN
-----------------------------------------------------------------
Index Scan using t_pkey on t (cost=0.42..8.44 rows=1 width=10)
Index Cond: (id = $1)
ããã§ã¯ããIndex CondïŒïŒid = $ 1ïŒããšããæ¡ä»¶ã§ãç¹å®ã®å€ã®ä»£ããã«ããã€ã³ãã£ã³ã°å€æ°ã®çªå·ã瀺ãããŠããŸã-ããã¯äžè¬çãªèšç»ã®å
åã§ãã ãã®å Žåã®ãã®äŸ¡å€ã¯ããã©ã€ããŒããã©ã³ã®ã³ã¹ããšäžèŽããŸãã
ããã§ãæ¢æã®èšç»ããªã¯ãšã¹ãã«äœ¿çšãããå®è¡ã®å¹çãåäžããŸãïŒãã ããã³ã¹ãã®èšç®ã«ãšã©ãŒãçºçããå ŽåããŸãã¯æåã®5åããææšã§ã¯ãªããå Žåã«åé¡ãçºçããå¯èœæ§ããããŸãïŒã
ãããã«
è§£æããããªã¯ãšã¹ãã®ã°ããŒãã«ãã£ãã·ã¥ãOracleã§äœ¿çšãããšããæ±ºå®ã¯ããµã€ãºã«å¶éããããæçšãªãã©ã³ãæ··ã¿åãå±éºæ§ããããããšããã£ãã·ã¥ã«ã¢ã¯ã»ã¹ããããã®äžŠåããã»ã¹ã®ç«¶åã®ããã«ã絶察ã«å¿
èŠãªãã®ãããå€ãæžã蟌ã¿ãããªããšãã顿ã«ã€ãªãããŸãã ãããã£ãŠãOracleã¯èŠæ±ã®1ã€ã®äžè¬çãªèšç»ããå§ãŸããå¿
èŠãªå Žåã«ã®ã¿ããã€ãã®åã«é²ã¿ãŸãã
ããã©ããããPostgresã§ã°ããŒãã«ãã£ãã·ã¥ã䜿çšããªããšããæ±ºå®ã«ãããäžå¿
èŠãªè§£æãšã®é¢é£ä»ãã容æã«ãªããŸãã å察ã«ãPostgresã¯ãã©ã€ããŒããã©ã³ããå§ãŸããå¯èœã§ããã°äžè¬çãªãã©ã³ã«ç§»è¡ããŸãã
Oracleã¯ãªã¯ãšã¹ãã®èšç»ãèªåçã«ãã£ãã·ã¥ããŸãã ãã®ç¹ã§ãéçºè
ã¯ãã€ã³ã倿°ã䜿çšããããšãèŠããŠããã ãã§ãããããã¯äž»ã«ã°ããŒãã«ãã£ãã·ã¥ã®å¶éã«ãã£ãŠæ±ºãŸããŸãã åé¡ã®é倧床ã«ãããOracleã¯cursor_sharingãã©ã¡ãŒã¿ãŒãæäŸãããã¹ãŠã®å®æ°ã倿°ã«çœ®ãæããŸãã
Postgresã¯ãè§£æããããªã¯ãšã¹ããéçºè
ãŸãã¯éçºããŒã«ã®æã«ä¿åããå¿
èŠæ§ãå®å
šã«å€æããŸãã ãã€ã³ã倿°ã®äœ¿çšã¯ãPostgresã®ããã©ãŒãã³ã¹ã«ããã»ã©åçãªåœ¹å²ãæãããŸããïŒãã ããSQLã€ã³ãžã§ã¯ã·ã§ã³ã®ã»ãã¥ãªãã£åé¡ã¯äž¡æ¹ã®ã·ã¹ãã ã«çããé¢é£ããŸãïŒã
è€æ°ã®ããã»ã¹ãåãã¯ãšãªã䜿çšããå ŽåãOracleã§è§£æãããã®ã¯1åã®ã¿ã§ãã æ®ãã®ããã»ã¹ã¯ãã°ããŒãã«ãã£ãã·ã¥å
ã®æ¢è£œã®ãã©ã³ãå©çšããŸãã
Postgresã§ã¯ãåããã»ã¹ã¯ãªã¯ãšã¹ãèªäœãè§£æããå¿
èŠããããŸãã ãã ãã1åéãã®èŠæ±ã¯ããã©ã³ããã£ãã·ã¥ã«å
¥ãããªãŒããŒããããªãã§å®è¡ãããŸãã
åãœãªã¥ãŒã·ã§ã³ã«ã¯é·æãšçæããããŸãã ãããã«ããŠãããããã®æ©èœã¯ãã¢ããªã±ãŒã·ã§ã³ã·ã¹ãã ãèšèšãå®è£
ãããã³ä¿å®ããéçºè
ããã³ç®¡çè
ãèæ
®ããå¿
èŠããããŸãã