Tuesday, October 14, 2014

Special Tuning Approach - selectively reorg the big customer's rows

For tuning the query that retrieves many rows made by big customers, it is needed some special technical approach.
Generally big customers make big rows compare to normal customers. So in using same query(SQL) there are huge differences in response time.
For example, in the ORDER_HIST table, normal customers make around 100 rows in a month whereas the big makes 10000 rows.
Response time of the normal is around 1 second whereas the big 100 seconds above.
In this case we can tune the query simply by reorganizing the rows of that big customers - that just delete and reinsert the rows.
The attached script is made for this special tuning remedy.
The effect of the result is depends on how the rows had widely dispersed before migrated.
If the rows now were much more clustered than before, then the effects will be amazing thanks to better clustering factor of now.



=============
 SCRIPT
=============
--for not stopping the service we should use 'for update' clause.
--for preventing Tx. Row Lock contention I bond every 1000 rows in one transaction rather than execute whole rows in a commit.
  If still occur Tx. Row Lock contention then lower the value from 1000 to ig. 100.

--in a SQL*Plus session

set serveroutput on

declare
  v_exe_unit_rows number := 1000; --rows per one Tx.
  v_tot_rows number      := 0;    --target rows to be reorged
  v_reorged_rows number  := 0;    --completed rows reorged
  v_commit_cnt number    := 0;    --count of commits
  
begin

  --target rows to be reorged
  select count(*)
  into v_tot_rows
  from   ORDER_HIST t
  where  acnt_num = 1111111111 --target customer
  ;
  
  for i in 1..trunc(v_tot_rows / v_exe_unit_rows)+1 loop
   
    if v_tot_rows > v_reorged_rows then
    
        for rec in ( --You should adopt sub-query for using 'for update' in Paging query
                    select t.rowid as rid, t.*
                    from ORDER_HIST t
                    where rowid in (
                                    select rid
                                    from (
                                            select /*+index(t N_ORDER_HIST_ACNT_NUM) */
                                                   t.rowid as rid
                                                 , rownum as rn
                                            from   ORDER_HIST t
                                            where  acnt_num = 1111111111 --target customer
                                            and rownum <= (i * v_exe_unit_rows)
                                            ) 
                                    where rn >= (i - 1) * v_exe_unit_rows + 1
                                    )
                    for update
                    ) loop

        --delete first
        delete ORDER_HIST
        where rowid = rec.rid;
        
        --insert later
        insert into ORDER_HIST values (
               rec.ACNT_NUM                 ,
               rec.PROD_NUM                 ,
               rec.CUST_NUM                 ,
               rec.ORDER_DTM                ,
               .
               .
               );
          
          v_reorged_rows := v_reorged_rows + 1;
          
        end loop;
        
        commit; --by 1000 rows
        v_commit_cnt := v_commit_cnt + 1;
     
    end if;
     
  end loop;     

  dbms_output.put_line('Total Rows    : ' || v_tot_rows );
  dbms_output.put_line('Reorged Rows  : ' || v_reorged_rows );
  dbms_output.put_line('commit  count : ' || v_commit_cnt );

exception
  when others then raise;
end;
/

No comments:

Post a Comment