実行計画でNESTED LOOPSを選択した際の外部表(駆動表)の選択について
事前準備
--table作成 create table tbl1(col1 number,col2 number,col3 number); create table tbl2(col1 number,col2 number,col3 number); --インデックス作成 CREATE INDEX tbl1_idx ON tbl1(col1); CREATE INDEX tbl2_idx ON tbl2(col1); --tbl1には10件投入 begin for i in 1..10 loop insert into tbl1 values(i,i,i); commit; end loop; end; / --tbl1には1000000件投入 begin for i in 1..1000000 loop insert into tbl2 values(i,i,i); commit; end loop; end; /
確認(読み込みブロック数と実行時間)
SQL> --tbl1(件数が少ない方を駆動表にする)
SQL> select /*+ USE_NL(tbl2) LEADING(tbl1) */count(1) from tbl1,tbl2 where tbl1.col2=tbl2.col2;
COUNT(1)
----------
10
経過: 00:00:00.55
実行計画
----------------------------------------------------------
Plan hash value: 1872982815
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 7508 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
| 2 | NESTED LOOPS | | 10 | 260 | 7508 (1)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TBL1 | 10 | 130 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| TBL2 | 1 | 13 | 751 (1)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("TBL1"."COL2"="TBL2"."COL2")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
統計
----------------------------------------------------------
9 recursive calls
0 db block gets
27616 consistent gets
0 physical reads
0 redo size
573 bytes sent via SQL*Net to client
451 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> --tbl2(件数が多い方を駆動表にする)
SQL> select /*+ USE_NL(tbl1) LEADING(tbl2) */count(1) from tbl1,tbl2 where tbl1.col2=tbl2.col2;
COUNT(1)
----------
10
経過: 00:00:06.35
実行計画
----------------------------------------------------------
Plan hash value: 835256089
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 301K (1)| 00:00:12 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
| 2 | NESTED LOOPS | | 10 | 260 | 301K (1)| 00:00:12 |
| 3 | TABLE ACCESS FULL| TBL2 | 1109K| 13M| 751 (1)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| TBL1 | 1 | 13 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("TBL1"."COL2"="TBL2"."COL2")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
統計
----------------------------------------------------------
7 recursive calls
0 db block gets
3002836 consistent gets
0 physical reads
0 redo size
573 bytes sent via SQL*Net to client
451 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
まとめ
実はあまり理解できていないのですが、どちらを駆動表にしてもレコードの組み合わせの個数は同じになります。 それでもtbl1の駆動表にした方が読み込みブロック数(処理時間も)が少なくなります。
docs.oracle.com 等を確認すると駆動表をフェッチしている(最初に対象データを絞る)らしいのでその分駆動表が小さい方が速いと勝手に理解しました。
Linuxのプロセス生成forkとexeclの違い
fork関数は呼び出したプロセスのコピープロセスを作成する
確認したプログラム
#include <stdio.h>
#include <unistd.h>
int main(void){
pid_t pid;
int i;
printf("start\n");
fork();
pid=getpid();
for(i=0;i<5;i++){
printf("pid=%d i=%d\n",pid,i);
}
}
実行結果
start pid=6438 i=0 pid=6438 i=1 pid=6438 i=2 pid=6438 i=3 pid=6438 i=4 pid=6439 i=0 pid=6439 i=1 pid=6439 i=2 pid=6439 i=3 pid=6439 i=4
execl関数は別のプログラムを実行する
確認したプログラム
#include <stdio.h>
#include <unistd.h>
int main(void){
printf("start\n");
execl("/bin/ls","/bin/ls","-l",NULL);
printf("finish\n");
return 0;
}
実行結果
lsコマンドが実行される。別のプロセスに置換されるため「printf("finish\n");」は実行されない
start 合計 480 -rw-------. 1 root root 1795 4月 21 22:59 anaconda-ks.cfg -rwxr-xr-x 1 root root 8456 5月 3 15:42 exe -rw-r--r-- 1 root root 149 5月 3 15:42 exe.c -rw-r--r-- 1 root root 7039 5月 3 15:45 exec.log.2943 -rw-r--r-- 1 root root 28569 5月 3 15:44 exec.log.5652 -rwxr-xr-x 1 root root 8560 5月 1 21:44 flk -rw-r--r-- 1 root root 177 5月 1 21:44 flk.c -rw-r--r--. 1 root root 1843 4月 21 23:00 initial-setup-ks.cfg -rw-r--r-- 1 root root 391626 4月 30 20:51 listener.log -rw-r--r-- 1 root root 7041 5月 3 15:23 test.log.2943 -rw-r--r-- 1 root root 4542 5月 3 15:23 test.log.4314 -rw-r--r-- 1 root root 292 5月 3 15:23 test.log.4315
sqlplusのプロセスを確認する
ローカル接続(リスナーを経由しない場合)
sqlplusとサーバプロセスの間に親子関係がある
[root@localhost ~]# ps -ef |grep 9433| grep -v grep oracle 9433 3998 0 21:03 pts/0 00:00:00 sqlplus as sysdba oracle 9434 9433 0 21:03 ? 00:00:00 oracleorcl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq))) [root@localhost ~]#
リモート接続(リスナーを経由する場合)
sqlplusとサーバプロセスの間に親子関係がない。 リスナーからfork()??exec()??されているかららしい。
[root@localhost ~]# ps -ef |grep 9811|grep -v grep oracle 9811 1 0 21:09 ? 00:00:00 oracleorcl (LOCAL=NO) [root@localhost ~]# ps -ef |grep sqlplus|grep -v grep oracle 9809 3998 0 21:09 pts/0 00:00:00 sqlplus [root@localhost ~]#
LinuxでCPU使用率を上げる(使用率を上げた後にsarコマンドで確認)
CPUの数を確認
# cat /proc/cpuinfo | grep processor processor : 0 processor : 1 #
2つ存在することを確認
一方のCPUに負荷をかける
実行コマンドyes >> /dev/null &
sarコマンドで確認
12:54:20 PM CPU %user %nice %system %iowait %steal %idle 12:54:25 PM all 29.70 0.00 20.40 0.00 0.00 49.90 12:54:25 PM 0 59.28 0.00 40.72 0.00 0.00 0.00 12:54:25 PM 1 0.00 0.00 0.00 0.00 0.00 100.00
参考にさせていただいたサイト
oerrコマンドでエラーの内容を調べることが可能
[oracle@localhost ~]$ oerr ora 1555 01555, 00000, "snapshot too old: rollback segment number %s with name \"%s\" too small" // *Cause: rollback records needed by a reader for consistent read are // overwritten by other writers // *Action: If in Automatic Undo Management mode, increase undo_retention // setting. Otherwise, use larger rollback segments [oracle@localhost ~]$ oerr ora 0001 00001, 00000, "unique constraint (%s.%s) violated" // *Cause: An UPDATE or INSERT statement attempted to insert a duplicate key. // For Trusted Oracle configured in DBMS MAC mode, you may see // this message if a duplicate entry exists at a different level. // *Action: Either remove the unique restriction or do not insert the key. [oracle@localhost ~]$
sarコマンドでネットワーク使用状況を確認
コマンド
sar -n DEV 1
ループバックアドレスにpingした状態で実行
実行コマンド
sar -n DEV 1|grep -e lo -e IFACE
実行結果
22時27分59秒 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s 22時28分00秒 lo 2.00 2.00 0.16 0.16 0.00 0.00 0.00
シェルスクリプトの中でsqlplusを実行
内容
ユーザ名(第1引数)、パスワード(第2引数)を渡し、test.sqlを10秒ごとに10回実行する。
#/bin/bash username="$1" password="$2" SLEEP_TIME=10 MAX_LOOP_COUNT=10 LOOP_COUNT=0 script_file="test.sql" while [ $LOOP_COUNT -lt $MAX_LOOP_COUNT ] do cat "${script_file}" |sqlplus -s ${username}/${password} LOOP_COUNT=`expr $LOOP_COUNT + 1` done