DBMS Tuning & My Life

The performance of partition outer join is better than Cartesian product join, in my case.

leave a comment »

In my previous post, I was mentioned about partition out join. This time I took performance test of partition outer join. Maybe, the result of the performance test depends on the test environment. But my test result shows that partition outer join is better than Cartesian product join.

(1) Create a table and test data loading.

CREATE TABLE t2( site CHAR( 100 ) , item CHAR( 100 ) , category CHAR( 100 ) , amount NUMBER ) ; 

--#of Branch : 10000
--#of Item : 5
--#of Category : 10

INSERT
INTO t2
SELECT 'Site-' ||lpad( site , 5 , '0' ) site ,
       'Item-' ||lpad( decode( item , 0 , 5 , item ) , 2 , '0' ) item ,
       'Category-' ||lpad( decode( category , 0 , 10 , category ) , 2 , '0' ) category ,
       amount
FROM (
      SELECT NTILE( 10000 ) over (ORDER BY LEVEL) site ,
             MOD( NTILE( 50000 ) over (ORDER BY LEVEL) , 5 ) item ,
             MOD( LEVEL , 10 ) category ,
             LEVEL amount
      FROM dual
      CONNECT BY LEVEL <=500000
      ) a ;
commit;

-- delete 5 rows
delete from t2 where site='Site-00010' and item='Item-04' and category between 'Category-03' and 'Category-07';

commit; 

(2) The result of Cartesian join method.

alter system flush buffer_cache; 

WITH v1 AS (
         SELECT a.site ,
            a.item ,
            a.category ,
            SUM( a.amount ) amount
         FROM t2 a
         GROUP BY a.site ,
            a.item ,
            a.category
      )
SELECT v2.site ,
      v2.item ,
      v2.category ,
      NVL( v1.amount , 0 ) amount
FROM  v1 ,
      (
       SELECT a.site ,
              a.item ,
              copy.category
       FROM   v1 a ,
              (
               SELECT
               CASE LEVEL
                   WHEN  1  THEN  'C01' 
                   WHEN  2  THEN  'C02' 
                   WHEN  3  THEN  'C03'  
                   WHEN  4  THEN  'C04'   
                   WHEN  5  THEN  'C05'
                   WHEN  6  THEN  'C06' 
                   WHEN  7  THEN  'C07'
                   WHEN  8  THEN  'C08'
                   WHEN  9  THEN  'C09'
                   WHEN  10 THEN  'C10'
               END category
               FROM   dual
               CONNECT BY level<=10
              ) copy
       GROUP  BY a.site ,
              a.item ,
              copy.category
      ) v2
WHERE v1.site( + ) = v2.site
AND   v1.item( + ) = v2.item
AND   v1.category( + ) = v2.category
ORDER BY 1 ,  2 ,  3 

call     count       cpu    elapsed       disk      query    current       rows        mis   Wait Ela
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Parse        1      0.56       3.91        489        660          2          0          1       0.00
Exec         1     30.59      37.13      39885      22029      22085          0          0      14.51
Fetch    20001    228.03     454.96     328712      43490         12     500000          0     328.10
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Total    20003    259.18     496.00     369086      66179      22099     500000          1     342.61

Event waited on                             Count Zero Ela     Elapse   AVG(Ela)   MAX(Ela)   Blocks
---------------------------------------- -------- -------- ---------- ---------- ---------- --------
enq: RO - fast object reuse                     2        0       0.04       0.02       0.02        0
Disk file operations I/O                        2        0       0.00       0.00       0.00        0
db file sequential read                         4        0       0.03       0.01       0.02        4
SQL*Net message to client                   20002        0       0.09       0.00       0.00        0
direct path write temp                       3025        0      47.95       0.02       0.30        0
log file sync                                   1        0       0.01       0.01       0.01        0
direct path read                               65        0       1.44       0.02       0.11        0
SQL*Net message from client                 20002        0      41.10       0.00       4.64        0
reliable message                                2        0       0.01       0.00       0.01        0
direct path sync                                1        0       0.05       0.05       0.05        0
direct path read temp                       24749        0     256.52       0.01       0.34        0

Rows       Row Source Operation
---------- ---------------------------------------------------
    500000 TEMP TABLE TRANSFORMATION  (cr=65519 pr=368597 pw=209624 time=485942990 us)
         0  LOAD AS SELECT  (cr=22029 pr=39885 pw=39781 time=37084935 us)
    499995   HASH GROUP BY (cr=22029 pr=39883 pw=18042 time=26659340 us cost=6166 size=226319654 card=709466)
    499995    TABLE ACCESS FULL T2 (cr=22029 pr=21841 pw=0 time=2615698 us cost=6089 size=226319654 card=709466)
    500000  SORT ORDER BY (cr=43490 pr=328712 pw=169843 time=447605455 us cost=40396 size=111312432 card=210819)
    500000   HASH JOIN OUTER (cr=43490 pr=315195 pw=156326 time=421193398 us cost=16810 size=111312432 card=210819)
    500000    VIEW  (cr=21746 pr=276820 pw=139691 time=263743564 us cost=8440 size=1045 card=5)
    500000     HASH GROUP BY (cr=21746 pr=276820 pw=139691 time=262628114 us cost=8440 size=1045 card=5)
   4999950      MERGE JOIN CARTESIAN (cr=21746 pr=149950 pw=12821 time=197411590 us cost=8363 size=148278394 card=709466)
        10       VIEW  (cr=0 pr=0 pw=0 time=952 us cost=2 size=5 card=1)
        10        CONNECT BY WITHOUT FILTERING (cr=0 pr=0 pw=0 time=719 us)
         1         FAST DUAL  (cr=0 pr=0 pw=0 time=16 us cost=2 size=0 card=1)
   4999950       BUFFER SORT (cr=21746 pr=149950 pw=12821 time=186241554 us cost=8440 size=144731064 card=709466)
    499995        VIEW  (cr=21746 pr=21740 pw=0 time=3686685 us cost=8361 size=144731064 card=709466)
    499995         TABLE ACCESS FULL SYS_TEMP_0FD9D6C8A_283648BD (cr=21746 pr=21740 pw=0 time=2634086 us cost=8361 size=226319654 card=709466)
    499995    VIEW  (cr=21744 pr=21740 pw=0 time=4269514 us cost=8361 size=226319654 card=709466)
    499995     TABLE ACCESS FULL SYS_TEMP_0FD9D6C8A_283648BD (cr=21744 pr=21740 pw=0 time=3210517 us cost=8361 size=226319654 card=709466)

(3) The result of partition outer join method.

alter system flush buffer_cache;

WITH v1 AS (
           SELECT a.site ,
                  a.item ,
                  a.category ,
                  SUM( a.amount ) amount
           FROM   t2 a
           GROUP  BY a.site ,
                  a.item ,
                  a.category
     )
SELECT a.site ,
     a.item ,
     copy.category ,
     NVL( a.amount , 0 )
FROM (
      SELECT
      CASE LEVEL
          WHEN  1  THEN  'C01'
          WHEN  2  THEN  'C02'
          WHEN  3  THEN  'C03'
          WHEN  4  THEN  'C04'
          WHEN  5  THEN  'C05'
          WHEN  6  THEN  'C06'
          WHEN  7  THEN  'C07'
          WHEN  8  THEN  'C08'
          WHEN  9  THEN  'C09'
          WHEN  10 THEN  'C10'
      END category
      FROM   dual
      CONNECT BY level &lt;=10
     ) copy left outer join v1 a PARTITION BY ( a.site , a.item ) ON copy.category = a.category
ORDER BY 1 , 2, 3

call     count       cpu    elapsed       disk      query    current       rows        mis   Wait Ela
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Parse        1      0.34       2.51        451        277          1          0          1       0.00
Exec         1      0.00       0.00          0          0          0          0          0       0.00
Fetch    20001    109.33     142.74      94971      22029         23     500000          0      91.02
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Total    20003    109.67     145.25      95422      22306         24     500000          1      91.02

Event waited on                             Count Zero Ela     Elapse   AVG(Ela)   MAX(Ela)   Blocks
---------------------------------------- -------- -------- ---------- ---------- ---------- --------
Disk file operations I/O                        1        0       0.00       0.00       0.00        0
direct path write temp                       1703        0      42.50       0.02       0.25        0
SQL*Net message to client                   20002        0       0.10       0.00       0.00        0
direct path read                               50        0       1.01       0.02       0.12        0
SQL*Net message from client                 20002        0      43.22       0.00       4.98        0
direct path read temp                        3517        0       9.17       0.00       0.32        0

Rows       Row Source Operation
---------- ---------------------------------------------------
    500000 SORT ORDER BY (cr=22029 pr=94971 pw=73130 time=192705062 us cost=55040 size=1575090 card=7095)
    500000  VIEW  (cr=22029 pr=81457 pw=59616 time=120167261 us cost=54694 size=1575090 card=7095)
    500000   NESTED LOOPS PARTITION OUTER (cr=22029 pr=81457 pw=59616 time=118555905 us cost=54694 size=2298780 card=7095)
    500001    BUFFER SORT (cr=0 pr=0 pw=0 time=1818543 us)
        10     VIEW  (cr=0 pr=0 pw=0 time=487 us cost=2 size=5 card=1)
        10      CONNECT BY WITHOUT FILTERING (cr=0 pr=0 pw=0 time=405 us)
         1       FAST DUAL  (cr=0 pr=0 pw=0 time=10 us cost=2 size=0 card=1)
         0    FILTER  (cr=22029 pr=81457 pw=59616 time=107572004 us)
   4999950     SORT PARTITION JOIN (cr=22029 pr=81457 pw=59616 time=100176688 us cost=54681 size=2263305 card=7095)
    499995      VIEW  (cr=22029 pr=61849 pw=40008 time=52874935 us cost=6166 size=2263305 card=7095)
    499995       SORT GROUP BY (cr=22029 pr=61849 pw=40008 time=51216115 us cost=6166 size=226319654 card=709466)
    499995        TABLE ACCESS FULL T2 (cr=22029 pr=21841 pw=0 time=2415314 us cost=6089 size=226319654 card=709466)

Written by sean70kim

July 7, 2013 at 2:27 am

Posted in Oracle

Tagged with

The simple example of partition outer join.

leave a comment »

Partition outer join was introuced at Oracle 10g. The feature of partition outer join is very useful, especially, when you make a UI query. Suppose, you are a sales manager and you should anlayze the sales report everyday. So, you want a user-friendly report template. For example, the layout of second report is more user-friendly than first report.

The layout of first report.
outerjoin01

The layout of second report.
outerjoin02

To make the layout of scecondary report, we usually use catesian product join. like this.

create table t1 (
  site     char(10),
  item     char(10),
  category char(10),
  amount   number);
 
insert into t1
select 'SITE'||case when level<=8 then '01' else '02' end,
       'ITEM'||case when level<=8 then '01' else '02' end,
       'C'||lpad(to_char(mod(level,8)+1),2,'0'),
       level*100
from   dual connect by level<=16;

commit;
 
with v1 as(
 select a.site, a.item, a.category, sum(a.amount) amount
 from   t1 a
 group  by a.site, a.item, a.category
)
select v2.site, v2.item, v2.category, nvl(v1.amount,0) amount 
  from v1, ( select a.site, a.item, copy.category
               from v1 a, (select case level when 1  then 'C01'
                                             when 2  then 'C02'
                                             when 3  then 'C03'
                                             when 4  then 'C04'
                                             when 5  then 'C05'
                                             when 6  then 'C06'
                                             when 7  then 'C07'
                                             when 8  then 'C08'
                                             when 9  then 'C09'
                                             when 10 then 'C10' end category
                          from dual connect by level<=10) copy
             group by a.site, a.item, copy.category) v2
where v1.site(+)     = v2.site
and   v1.item(+)     = v2.item
and   v1.category(+) = v2.category 
order by 1,2,3;

But, from oracle 10g, we can use partition outer join method, like this.

with v1 as(
 select a.site, a.item, a.category, sum(a.amount) amount
 from   t1 a
 group  by a.site, a.item, a.category
)
select a.site, a.item, copy.category, nvl(a.amount,0)
from  (select case level when 1  then 'C01'
                         when 2  then 'C02'
                         when 3  then 'C03'
                         when 4  then 'C04'
                         when 5  then 'C05'
                         when 6  then 'C06'
                         when 7  then 'C07'
                         when 8  then 'C08'
                         when 9  then 'C09'
                         when 10 then 'C10' end category
        from dual connect by level<=10) copy
left outer join v1 a
PARTITION BY (a.site, a.item)
on copy.category = a.category
order by 1,2;

Written by sean70kim

July 7, 2013 at 2:19 am

Posted in Oracle

Tagged with

One of the internal mechanisms of IOT.

leave a comment »

When was the IOT’s PK column(s) updated, what will happen to the secondary index?

In the oracle world, IOT is not frequently used. Actually, I don’t know the reason. Because IOT can provide good peformance in many cases. Of course, IOT has some restrictions. For example, it can’t use direct load and so on. Anyway, this time we reveal one of the mechanisms of IOT.

As you already know, IOT can have a seconary index. And the leaf blocks of the seconary index include index key column, PK column(s) and physical guess (= Data Block Address). So, to find the proper data block, oracle initially uses a physical guess. If the physical guess isn’t correct, use the PK column(s) in secondary index.

If so, when was the IOT’s PK column(s) updated, what will happen to the secondary index? That is a very simple question. Maybe the contents of the secondary index will be changed. Let’s prove that.
Read the rest of this entry »

Written by sean70kim

July 7, 2013 at 2:07 am

Posted in Oracle

Tagged with ,

PostgreSQL advanced server supports some optimizer hints.

leave a comment »

Optimizer Hints are very useful feature for query performance tuning.

There is diversity of opinion that use of optimizer hints. But, It’s true that optimizer hints are very convenient way to statement tuning. So, almost DBMS vendors support optimizer hint. But, PostgreSQL doesn’t suppot optimizer hint. Instead of, PostgreSQL supports “planner method configuration”. For example, in case of join method, PostgreSQL supports “enable_hashjoin”, “enable_nestloop”, “enable_mergejoin”. So, if you need more than two join methods in a statement, “planner method configuration” maybe can’t control query execution plan that you want. That is very dangerous from a performance perspective.

Fortunately, PostgreSQL advanced server supports some optimizer hints. For example, ORDERED, INDEX, NO_INDEX, FULL, FIRST_ROWS, USE_NL, USE_HASH and so on. That is very basic hints for join order, access method and join method. And, there isn’t hints for sub query, view merge, push predicate and so on. But, basic hints can cover a lot of bad sql statement. Below is the result of my simple test.
Read the rest of this entry »

Written by sean70kim

July 7, 2013 at 1:54 am

Posted in postgreSQL

Tagged with

From 11g, you can use DBMS_SPM to influence the execution plan without changing the sql statement.

leave a comment »

Until 10g, oracle provided outline and sql_profile package to influence execution plan without changing sql statement. And from 11g, oracle provide DBMS_SPM.

1) Create a sample table and a index.

SQL> create table t1 as
select '1' col1 ,
       LEVEL col2 ,
       mod(LEVEL , 10000 ) col3 ,
       'dummy' col4
from   dual
connect by level <=100000; 

SQL> create unique index t1_uk on t1 (col1, col2, col3) nologging; 
SQL> create index t1_idx1 on t1 (col3) nologging; 
SQL> exec dbms_stats.gather_table_stats(user,'t1');

2) Execute the bad sql statement.
Oracle optimizer choose T1_UK index, but col2 range is wide. So that is bad choise.

SQL> var b1 char(1);
SQL> var b2 number;
SQL> var b3 number;
SQL> var b4 number
SQL> exec :b1:='1';
SQL> exec :b2:=1
SQL> exec :b3:=50000
SQL> exec :b4:=1000 

SQL> SELECT *
FROM   t1
WHERE  col1=:b1
AND    col2 BETWEEN :b2 AND :b3
AND    col3=:b4;
 
call     count       cpu    elapsed       disk      query    current       rows        mis   Wait Ela
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Parse        1      0.01       0.01          0          0          0          0          1       0.00
Exec         1      0.00       0.01          0          0          0          0          0       0.00
Fetch        1      0.06       0.06          0        151          0          5          0       0.00
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Total        3      0.07       0.07          0        151          0          5          1       0.00
 
Rows       Row Source Operation
---------- ---------------------------------------------------
         5 FILTER  (cr=151 pr=0 pw=0 time=45586 us)
         5  TABLE ACCESS BY INDEX ROWID T1 (cr=151 pr=0 pw=0 time=45509 us cost=4 size=17 card=1)
         5   INDEX RANGE SCAN T1_UK (cr=146 pr=0 pw=0 time=45307 us cost=3 size=0 card=1) 

3) Find sql_id of bad sql statement.

SQL> SELECT sql_id, plan_hash_value, sql_text from v$sql where sql_text like '%col2 BETWEEN :b2 AND :b3%'
 
SQL_ID         PLAN_HASH_VALUE  SQL_TEXT
-------------- ---------------- ---------------------------------------------
1mkrscbk593ut  555629870        SELECT * FROM   t1 WHERE  col1=:b1 AND    col 

4) Create a sql plan baseline for the bad sql statement.

$ sqlplus "/ as sysdba"
 
SQL> var cnt number;
SQL> exec :cnt:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'1mkrscbk593ut');

SQL> col sql_handle for a20
SQL> col plan_name  for a40

SQL> SELECT sql_handle ,
       plan_name ,
       enabled
FROM   dba_sql_plan_baselines
WHERE  signature IN (
                     SELECT exact_matching_signature
                     FROM   v$sql
                     WHERE  sql_id='1mkrscbk593ut'
       )
   
SQL_HANDLE           PLAN_NAME                                ENABLE
-------------------- ---------------------------------------- ------
SQL_32cd48c2f499da8d SQL_PLAN_35ma8sbu9mqnde4162105           YES 

5) Captured plan is not efficient, so it should be disabled.

 SQL> exec :cnt:=dbms_spm.alter_sql_plan_baseline(sql_handle=>'SQL_32cd48c2f499da8d', -
 plan_name=>'SQL_PLAN_35ma8sbu9mqnde4162105', -
 attribute_name=>'enabled', -
 attribute_value=>'NO');

6) Modify sql statement to use hint & execute it.

SQL> select /*+ index(t1 t1_idx1) */
      * from t1
 where col1=:b1
 and   col2 between :b2 and :b3
 and   col3=:b4
 
 call     count       cpu    elapsed       disk      query    current       rows        mis   Wait Ela
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Parse        1      0.01       0.00          0          0          0          0          1       0.00
Exec         1      0.01       0.01          0          0          0          0          0       0.00
Fetch        1      0.00       0.00          0         12          0          5          0       0.00
------- ------  -------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Total        3      0.02       0.01          0         12          0          5          1       0.00
 
Event waited on                             Count Zero Ela     Elapse   AVG(Ela)   MAX(Ela)   Blocks
---------------------------------------- -------- -------- ---------- ---------- ---------- --------
SQL*Net message to client                       2        0       0.00       0.00       0.00        0
SQL*Net message from client                     2        0       0.00       0.00       0.00        0
 
Rows       Row Source Operation
---------- ---------------------------------------------------
         5 FILTER  (cr=12 pr=0 pw=0 time=739 us)
         5  TABLE ACCESS BY INDEX ROWID T1 (cr=12 pr=0 pw=0 time=670 us cost=11 size=17 card=1)
        10   INDEX RANGE SCAN T1_IDX1 (cr=2 pr=0 pw=0 time=282 us cost=1 size=0 card=10) 

7) Find sql_id and plan_hash_value for hinted sql statement.

SQL> SELECT sql_id, plan_hash_value, sql_text from v$sql where sql_text like '%/*+ index(t1 t1_idx1) */%'
 
SQL_ID         PLAN_HASH_VALUE    SQL_TEXT
-------------- ------------------ ---------------------------------------
6q33rurh1snrg  1633758621         select /*+ index(t1 t1_idx1) */ * from 

8) Change bad sql execution plan to hinted sql execution plan.

SQL> exec :cnt:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'6q33rurh1snrg',-
 plan_hash_value=> 1633758621, -
 sql_handle=>'SQL_32cd48c2f499da8d'); 
 
 *) sql_id => sql_id of hinted sql statement 
 *) plan_hash_value => plan_hash_value of hinted sql statement 
 *) sql_handle => sql_handle of bad sql statement

9) Run bad sql and check the result of execution plan.

SQL> SELECT *
FROM t1
WHERE col1=:b1
AND col2 BETWEEN :b2 AND :b3
AND col3=:b4;

SQL> select * from table(DBMS_XPLAN.DISPLAY_CURSOR('1mkrscbk593ut', null)); 
PLAN_TABLE_OUTPUT
SQL_ID  1mkrscbk593ut, child number 0
-------------------------------------
SELECT * FROM   t1 WHERE  col1=:b1 AND    col2 BETWEEN :b2 AND :b3 AND
  col3=:b4
 
Plan hash value: 555629870 
--------------------------------------------------------------------------------------
| Id  | Operation                    | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |       |       |       |     4 (100)|          |
|*  1 |  FILTER                      |       |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| T1    |     1 |    17 |     4   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | T1_UK |     1 |       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
--------------------------------------------------- 
   1 - filter(TO_NUMBER(:B2)<=TO_NUMBER(:B3))
   3 - access("COL1"=:B1 AND "COL2">=TO_NUMBER(:B2) AND "COL3"=TO_NUMBER(:B4)
              AND "COL2"<=TO_NUMBER(:B3))
       filter("COL3"=TO_NUMBER(:B4))

 SQL_ID  1mkrscbk593ut, child number 1
-------------------------------------
SELECT * FROM   t1 WHERE  col1=:b1 AND    col2 BETWEEN :b2 AND :b3 AND
  col3=:b4
 
Plan hash value: 1633758621 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |       |       |    11 (100)|          |
|*  1 |  FILTER                      |         |       |       |            |          |
|*  2 |   TABLE ACCESS BY INDEX ROWID| T1      |     5 |    85 |    11   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | T1_IDX1 |    10 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
--------------------------------------------------- 
   1 - filter(TO_NUMBER(:B2)<=TO_NUMBER(:B3))
   2 - filter(("COL2"<=TO_NUMBER(:B3) AND "COL1"=:B1 AND
              "COL2">=TO_NUMBER(:B2)))
   3 - access("COL3"=TO_NUMBER(:B4))
 
Note
-----
   - SQL plan baseline SQL_PLAN_35ma8sbu9mqnd97e27072 used for this statement

There are two child cursor (cursor number 0 and 1) in the v$sql. And, the execution plan of child cursor #1 is the same with the execution plan of hinted sql.

Written by sean70kim

July 7, 2013 at 1:26 am

Posted in Oracle

Tagged with ,

Identify root cause session using V$WAIT_CHAINS from 11g.

leave a comment »

From 11g, oracle provide V$WAIT_CHAINS dynamic performance view.
It’s very powerful and convenient to use. So, you can easily idenfify root cause session among the many sessions using that view. The contents of V$WAIT_CHAINS view are very similar with the section of the output of ‘hanganalyze 1’. So, you don’t need to anymore execute ‘hanganalyze’ oradebug command. Instead, you just run below query.

SELECT decode( a.blocker_sid , NULL , '<chain id#' ||a.chain_id||'>' ) chain_id,
       RPAD( '+' , LEVEL , '-' ) ||a.sid sid,
       RPAD( ' ' , LEVEL , ' ' ) ||a.wait_event_text wait_event
FROM   V$WAIT_CHAINS  a
CONNECT BY PRIOR a.sid=a.blocker_sid
AND    PRIOR a.sess_serial#=a.blocker_sess_serial#
AND    PRIOR a.instance = a.blocker_instance START WITH a.blocker_is_valid='FALSE'
ORDER  BY a.chain_id ,
       LEVEL
/
 
CHAIN_ID             SID        WAIT_EVENT
-------------------- ---------- --------------------------------------------------
<chain id#1>         +190        SQL*Net message from client
                     +-4          enq: TX - row lock contention
<chain id#2>         +221        SQL*Net message from client
                     +-108        enq: TX - row lock contention
                     +--8          enq: TX - row lock contention
<chain id#3>         +67         SQL*Net message from client
                     +-155        enq: TX - row lock contention
                     +--146        enq: TX - row lock contention
                     +-156        enq: TX - row lock contention 
 

Written by sean70kim

July 7, 2013 at 1:16 am

Posted in Oracle

Tagged with ,

Monitoring OPI(Oracle Program Interface) call using 10051 event.

leave a comment »

OPI call is the abbreviation of Oracle Program Interface. Whenever you issue a statement to oracle, client Program sends OPI call to oracle. And, you can monitor OPI call using 10051 event.
I am wondering why the count of fetch call is 2 even if only fetch 1 rows. 10051 event gives some idea to understand that reason.

  SQL> create table t1 (c1 number); 
  SQL> insert into t1 values (1); 
  SQL> insert into t1 values (2); 
  SQL> insert into t1 values (3); 

  -- for monitor OPI call 
  SQL> alter session set events '10051 trace name context forever, level 1';   
 
  -- for monitor statistics 
  SQL> alter session set events '10046 trace name context forever, level 12'; 
 
  SQL> select * from t1;  

The result of trace file is below that.

WAIT #18446744071470144568: nam='SQL*Net message from client' ela= 10117632 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=23918731137420
OPI CALL: type=105 argc= 2 cursor= 0 name=Cursor close all
CLOSE #18446744071470144568:c=0,e=48,dep=0,type=1,tim=23918731138070
OPI CALL: type=94 argc=28 cursor= 0 name=V8 Bundled Exec
=====================
PARSING IN CURSOR #18446744071470143696 len=16 dep=0 uid=84 oct=3 lid=84 tim=23918731138758 hv=2245880055 ad='3d1a7d708' sqlid='27uhu2q2xuu7r'
select * from t1
END OF STMT
PARSE #18446744071470143696:c=0,e=347,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=838529891,tim=23918731138752
EXEC #18446744071470143696:c=0,e=214,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=838529891,tim=23918731139421
WAIT #18446744071470143696: nam='SQL*Net message to client' ela= 8 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=23918731139743
FETCH #18446744071470143696:c=0,e=616,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,plh=838529891,tim=23918731140542
WAIT #18446744071470143696: nam='SQL*Net message from client' ela= 713 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=23918731141761
OPI CALL: type= 5 argc= 2 cursor= 2 name=FETCH
FETCH #18446744071470143696:c=0,e=129,p=0,cr=3,cu=0,mis=0,r=2,dep=0,og=1,plh=838529891,tim=23918731142142
STAT #18446744071470143696 id=1 cnt=1 pid=0 pos=1 obj=150847 op='TABLE ACCESS FULL T1 (cr=7 pr=0 pw=0 time=561 us cost=3 size=13 card=1)'
WAIT #18446744071470143696: nam='SQL*Net message to client' ela= 5 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=23918731142629

There are three OPI calls in the trace file. The names of OPI call are ‘Cursor close all’, ‘V8 bundled Exec’, ‘Fetch’. ‘Cursor close all’ and ‘V8 bundled Exec’ are some odd. Until now I think that if I issue a select statement to oracle, then oracle needs parse call, execute call and fetch call. so 3 user calls recorded in v$sesstat that session. But that is not correct. Whenever, issue a select statement, first of all, oracle closes all open cursor and the bundled Exec. Bundled Exec means that exec call includes parse call. And that mechanism is applied to oracle V8. And last, fetch call is performed.

And between ‘V8 bundled Exec’ and ‘Fetch’ OPI call, oracle perform 1 FETCH call to fetch 1 row (r=1). And after ‘Fetch’ OPI call, oracle FETCH next rows. even if the total number of records that was satisfied WHERE condition is only 1. so, The number of fetch call is 2 in the trace file. below is the output of tkprof.

select * from t1 

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0          7          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0          7          0           1

PS) Thanks for Tanel Poder for his hacking session. How Oracle SQL Plans Are Really Executed – Part 1.

Written by sean70kim

July 7, 2013 at 1:10 am

Posted in Oracle

Tagged with , ,

The mechanism of Index Skip Scan operation.

leave a comment »

What’s the mechanism of index skip scan operation?

Index skip scan was introduced at oracle 9i. As always, new features have pros and cons. So, we must perfectly understand that mechanism.

Why do we need index skip scan operation?

Basically, until 8i, composite index can only be used if the first column exists in the WHERE clause. If index IDX1 is composed of COL1 and COL2, and in the WHERE clause only COL2 exists, then oracle can’t use IDX1 index. COL1 dosen’t exist in the WHERE clause. In that case, if you want to use the index without modifing the query, then you must create an index that has leading edge columns is COL2. But that is a very inefficient work.

How index skip scan operation work?

So, in oracle 9i, oracle coperation introduces index skip scan. That operation can use index even though, the first column dosen’t exist in the WHERE clause. So, oralce query optimizer could be uses the index. And you can also use INDEX_SS hint to control the execution plan. That seems to be very efficient. Really?
Read the rest of this entry »

Written by sean70kim

July 7, 2013 at 1:01 am

Posted in Oracle

Tagged with , ,

postgreSQL-XC 1.0.2 installation guide.

leave a comment »

The postgreSQL-XC is simple and powerful cluster solution. My environment for installation is below that.

  • # of database server –> 2 linux servers
  • # of datanode in each database server –> 2 ( total 4 datanodes in cluster)
  • # of coordinator in each database server –> 2
  • # of gtm in each database server –> 2
  • postgreSQL version –> 9.1.7

pre-installation
if postgreSQL is not installed on server then you must install postgreSQL.

1) Download postgreSQL
Download postgresql-9.2.3.tar.gz

2) Install postgreSQL
— upload tar file to server using FTP.
— and login to linux server (using postgres o/s user or any other user can)

$ gunzip postgresql-9.2.3.tar.gz
$ tar xvf postgresql-9.2.3.tar
$ cd postgresql-9.2.3
$ ./configure
$ make
$ su root
Password: *** * ( switch user to root for install)
# make install

Read the rest of this entry »

Written by sean70kim

July 5, 2013 at 8:06 am

Posted in postgreSQL

Tagged with ,

The mechanism of Exadata’s storage index.

leave a comment »

Storage Index (SI) is a unique feature of Oracle Exadata, but unfortunately Storage index has a few restriction.

Basic
Storage index (SI) is a unique feature of Oracle Exadata. The main purpose of SI is elimination of unnecessary disk I/O when a performing smart scan in order that SI was maintained in the memory of cellsrv. The concept of SI is very simple and efficient. SI maintains column’s MIN/MAX values of each 1M unit. So, if predicate value doesn’t belong to MIN/MAX boundary, then oracle can bypass that unit. It’s because all data in that unit isn’t related to that predicate value. And, we can measure the effectiveness of SI by “cell physical IO bytes saved by storage index” statistics.

Why well-ordered is important?
As mentioned in Basic section, SI maintains column’s MIN/MAX values of each 1M unit. So, well-ordered column is more benefit by SI. For example, in case of Case#1, oracle can bypass 2nd, 3rd unit. Because, the MIN values of these are greater than 3 (predicate value). But, in case of Case#2, oracle can’t bypass any unit.

Storage_Index

The restriction of SI
In my opinion, Below are the restrictions of SI (X2 version).
(1) SI isn’t permanent.
(2) SI can maintain only 8 columns.
(3) SI turns to invalid, when DML is occurred.
(4) SI doesn’t work until cellsrv restarted, if DATA_OBJECT_IS is changed.

(1) SI isn’t permanent.
SI is stored in memory, so whenever cellsrv is shutdown, SI disappear.

(2) SI can maintain only 8 columns.
Most tables have more than 8 columns. BTW, why SI can maintain only 8 columns? Actually, I don’t know that reason. But, I learned the maintain mechanism using field test. In conclusion, more efficient SI is more likely to survive.
For example, suppose that T1 table has 12 columns (c1~c12), and then run 8 sql statements like following. “select count(*) from t1 where c1=:b1;” ~ ” select count(*) from t1 where c8=:b1;”. Then, SI was created for columns c1~c8. Since then, run sql statement “select count(*) from t1 where c9=:b1;” What will happen? Oracle compare efficiency of SI for c9 column with SI that was created for T1 table. If c9 column is more efficient, then oracle drop the most inefficient SI. So, more efficient SI is more likely to survive.

(3) SI turns to invalid, when DML is occurred.
SI can’t apply the change in real time. So, if DML is occurred then SI turns to invalid. And, after next smart scan occurs, SI will be created.

(4) If DATA_OBJECT_IS is changed, SI doesn’t work until cellsrv restarted.
for example, TRUNCATE command change the DATA_OBJECT_ID. So, after then SI doesn’t work. Actually, I don’t know, that is design-intended function.

Written by sean70kim

July 5, 2013 at 1:29 am

Posted in Oracle

Tagged with ,