beacon ora perf class 1

Upload: tuancoi

Post on 14-Jan-2016

215 views

Category:

Documents


0 download

DESCRIPTION

Perf Class 1

TRANSCRIPT

  • 2007-12-251www.oracleact.com

    Oracle Performance Tuning

    Tamilselvan G

    B

    e

    a

    c

    o

    n

    In

    f

    o

    t

    e

    c

    h

    C

    o

    r

    p

    o

    r

    a

    t

    io

    n

    C

    l

    a

    s

    s

    -

    1

  • 2007-12-252www.oracleact.com

    Contents

    1. Table Types Normal (heap) table, Index Cluster, Hash Cluster, IOT, Partition,

    Global Temporary Table, External Table

    2. Table Access When to use Full Table Scan, NO ROT

    3. Avoiding accidental table scans Queries involved NOT EQUAL,

    Searching for NULL values, Using a function on the indexed column.

    4. Functional Indexes

    5. IOT Including clause, over flow

    6. Using Concatenated Index

    7. Index Merges Hint AND_EQUAL(tablename, index1, index2,)

    8. Searching for Ranges Unbounded Range Scan ( < or >) ; Bounded Range Scans

    ( between 2 values) ; Range Look Up ( value between lowvalue_column and

    highvolue_column)

    9. Queries Involving OR Useful Hint USE_CONCAT.

    10. INLIST Iterator

    11. Fast Full Index Scan

    12. Bind Variable and 5 Percent Guess

    13. Optimizing Full Table PCTFREE and PCTUSED

    14. Update Statement

  • 2007-12-253www.oracleact.com

    1 Table Types

    1.1 Relation Table Basic Structure to hold relational data

    Heap Table

    Index Cluster

    Hash Cluster

    Partition

    Global Temporary Table

    External Table

    1.2 Object Table Uses Object Type for a column definition

    INDEX CLUSTER

    A cluster provides an optional method of storing table data.

    A cluster is made up of a group of tables that share the same data blocks.

    The tables are grouped together because they share common columns and

    are often used together. Example, DEPTNO column in EMP and DEPT tables.

    To find or store a row in an indexed table or cluster, a minimum of two

    (there are usually more) I/Os must be performed:

    One or more I/Os to find or store the key value in the index

    Another I/O to read or write the row in the table or cluster

  • 2007-12-254www.oracleact.com

    CREATE CLUSTER EMP_DEPT (deptno NUMBER(3))

    SIZE 7000

    TABLESPACE users

    STORAGE (INITIAL 200K NEXT 300K MINEXTENTS 2

    MAXEXTENTS 20 PCTINCREASE 33);

    Create an index on the cluster.

    CREATE INDEX EMP_DEPT_INDEX

    ON CLUSTER EMP_DEPT

    TABLESPACE users

    STORAGE (INITIAL 50K NEXT 50K MINEXTENTS 2

    MAXEXTENTS 10 PCTINCREASE 33);

    Without an index on the cluster, you cannot insert rows into EMP and DEPT

    tables.

  • 2007-12-255www.oracleact.com

    Create tables on the cluster.

    CREATE TABLE DEPT (

    deptno NUMBER(3) PRIMARY KEY,

    deptname varchar2(30) )

    CLUSTER EMP_DEPT (deptno);

    CREATE TABLE EMP (

    empno NUMBER(5) PRIMARY KEY,

    ename VARCHAR2(15) NOT NULL, salary number(6),

    deptno NUMBER(3) REFERENCES dept)

    CLUSTER EMP_DEPT (deptno);

    Insert rows:

    insert into dept values (10,'Sales');

    insert into emp values (1001, 'Tamil',1000, 10);

    insert into emp values (1002, 'Tandon',2000,10) ;

    insert into dept values (20,'Marketing');

    insert into emp values (1003,'Muthu',3000,20);

    insert into emp values (1004,'Ravi',4000,20) ;

    commit;

  • 2007-12-256www.oracleact.com

    SQL> select dbms_rowid.rowid_relative_fno(rowid) file#,

    2 dbms_rowid.rowid_block_number(rowid) block#,

    3 a.*

    4* from dept a ;

    FILE# BLOCK# DEPTNO DEPTNAME

    ---------- ---------- ---------- ------------------------------

    3 3643 10 Sales

    3 3644 20 Marketing

    SQL> select dbms_rowid.rowid_relative_fno(rowid) file#,

    2 dbms_rowid.rowid_block_number(rowid) block#,

    3 a.*

    4* from emp a ;

    FILE# BLOCK# EMPNO ENAME SALARY DEPTNO

    ------ - --------- ---------- --------------- ---------- ----------

    3 3643 1001 Tamil 1000 10

    3 3643 1002 Tandon 2000 10

    3 3644 1003 Muthu 3000 20

    3 3644 1004 Ravi 4000 20

    Sh

    arin

    g

    of B

    locks

    am

    on

    g 2

    tab

    les

  • 2007-12-257www.oracleact.com

    Common ROWIDs among the tables:

    SQL> select rowid from emp

    2 intersect

    3 select rowid from dept ;

    ROWID

    ------------------

    AAAQrtAADAAAA47AAA

    AAAQrtAADAAAA48AAA

    .

    1. ROWID is not UNIQUE in the Database

    but in the table only.

    2. You should not use clusters for tables

    that are frequently accessed

    individually.

    3. If all the rows for a given cluster key

    value cannot fit in one block, the blocks

    are chained together to speed access to

    all the values with the given key. The

    cluster index points to the beginning of

    the chain of blocks, each of which

    contains the cluster key value and

    associated rows. If the cluster SIZE is

    such that more than one key fits in a

    block, blocks can belong to more than

    one chain.

  • 2007-12-258www.oracleact.com

    HASH CLUSTER

    Oracle document says

    To use hashing, you create a hash cluster and load tables into it. The database

    physically stores the rows of a table in a hash cluster and retrieves them

    according to the results of a hash function.

    Oracle Database uses a hash function to generate a distribution of numeric

    values, called hash values, that are based on specific cluster key values. The

    key of a hash cluster, like the key of an index cluster, can be a single column or

    composite key (multiple column key). To find or store a row in a hash cluster, the

    database applies the hash function to the cluster key value of the row. The

    resulting hash value corresponds to a data block in the cluster, which the

    database then reads or writes on behalf of the issued statement.

    The database uses a hash function to locate a row in a hash cluster; no I/O is

    required. As a result, a minimum of one I/O operation is necessary to read or

    write a row in a hash cluster.

  • 2007-12-259www.oracleact.com

    HASH CLUSTER

    CREATE CLUSTER call_detail_cluster (

    telephone_number NUMBER,

    call_timestamp NUMBER ,

    call_duration NUMBER )

    HASHKEYS 10000 HASH IS telephone_number

    SIZE 256;

    CREATE TABLE call_detail (

    telephone_number NUMBER,

    call_timestamp NUMBER ,

    call_duration NUMBER ,

    other_info VARCHAR2(30) )

    CLUSTER call_detail_cluster (

    telephone_number, call_timestamp, call_duration );

    When to HASH Cluster

    1. Predicate has equality condition

    2. Table is static.

  • 2007-12-2510www.oracleact.com

    2 When To Use Full Table Scan

    Many experts suggest to use full table scan when any or all of the following occur:

    More than 15 % of rows from the table are selected

    More than 25 % of Index blocks are accessed

    When a column has low selectivity and it is being used in the WHERE

    clause

    It is really very hard to determine whether full table scan is appropriate or not.

    There are many factors involved row length, number of rows in the table,

    whether LOB is stored in-line or out-of-line, number of rows selected etc

    If the table and indexes are analyzed, then CBO will decide whether a full table or

    index lookup is appropriate based on the statistics available at that time

    and predicates in the query.

  • 2007-12-2511www.oracleact.com

    Disabling Index Scan

    Concatenating with the character column or adding 0 to number column will

    disable index scan.

    3 Avoiding accidental full table scan

    3.1 Greater Than and NOT EQUAL

    SQL> var b1 number ;

    SQL> select * from ssn_region where reg_id > :b1 ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=500 Bytes=13500)

    1 0 TABLE ACCESS (BY INDEX ROWID) OF 'SSN_REGION' (Cost=3 Card=500 Bytes=13500)

    2 1 INDEX (RANGE SCAN) OF 'SSN_REGION_PK' (UNIQUE) (Cost=2 Card=90)

    Note: When the value of bind variable is not known, Oracle assumes 5 % of the table rows

    will be returned. (Card =500). The table has 10,000 rows.

    However, there are some situation, you may want to use full table

    scan, then you just add a hint /*+ full(table_name) */ . Use

    parallel hint, if the table is really very big, /*+ full(table_name)

    parallel(table_name, degree_of_parallelism) */ .

  • 2007-12-2512www.oracleact.com

    SQL>select * from ssn_region where reg_id :b1 ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=9999 Bytes=269973)

    1 0 TABLE ACCESS (FULL) OF 'SSN_REGION' (Cost=6 Card=9999 Bytes=269973)

    Since Reg_id is unique in the table, Oracle assumes (all rows - 1 row) will be returned,

    hence it opts for FULL table scan.

    3.2 NULL Search

    SQL> select * from ssn_region where low_ssn_num is null ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=1 Bytes=27)

    1 0 TABLE ACCESS (FULL) OF 'SSN_REGION' (Cost=6 Card=1 Bytes=27)

    Note: A null search stops index usage.

    Use default value instead of NULL, if the

    column is frequently checked for NULL value

  • 2007-12-2513www.oracleact.com

    3.3 Function on Indexed Column

    A function on a indexed will force the CBO to opt for full table scan.

    SQL>select * from ssn_region where to_char(low_ssn_num) = :b1 ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=1 Bytes=27)

    1 0 TABLE ACCESS (FULL) OF 'SSN_REGION' (Cost=6 Card=1 Bytes=27)

    Note: Rewrite the query.

    Example: to_char(low_ssn_num) = :b1 is same as

    low_ssn_num = to_number(:b1)

    4. FUNCTIONAL INDEXES

    SQL> select email_status, count(*) from cust_order group by email_status;

    EMAIL_STATUS COUNT(*)

    ------------------------------ ----------

    Not Sent 299

    Sent 23770

    SQL> alter session set QUERY_REWRITE_ENABLED=TRUE;

    Session altered.

    SQL> alter session set QUERY_REWRITE_INTEGRITY=TRUSTED;

    Session altered.

  • 2007-12-2514www.oracleact.com

    SQL> create index cust_order_idx on cust_order

    (decode(email_status,'Not Sent',1,NULL)) ;

    Index created.

    SQL> analyze table cust_order compute statistics

    2 for table

    3 for all indexes

    4 for all indexed columns ;

    Table analyzed.

    SQL> set autot on expla

    SQL> select count(*) from cust_order where email_status = 'Not Sent' ;

    COUNT(*)

    ----------

    299

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=17)

    1 0 SORT (AGGREGATE)

    2 1 TABLE ACCESS (FULL) OF 'CUST_ORDER' (Cost=3 Card=241 Bytes=4097)

    SQL> select count(*) from cust_order

    where decode(email_status,'Not Sent',1,NULL) = 1 ;

    COUNT(*)

    ----------

    299

  • 2007-12-2515www.oracleact.com

    SQL> analyze index cust_order_idx validate structure;

    Index analyzed.

    SQL> select lf_rows from index_stats;

    LF_ROWS

    ----------

    299

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=17)

    1 0 SORT (AGGREGATE)

    2 1 INDEX (RANGE SCAN) OF 'CUST_ORDER_IDX' (NON-UNIQUE) (Cost=1 Card=299 Bytes=5083)

    SQL> select table_name, index_name, num_rows, last_analyzed

    from user_indexes where table_name = 'CUST_ORDER' ;

    TABLE_NAME INDEX_NAME NUM_ROWS LAST_ANALYZED

    ------------ ----------------------- ---------- --------------------

    CUST_ORDER CUST_ORDER_IDX 299 18-FEB-2005 13:47:32

    SQL> select email_status, count(*) from cust_order group by email_status;

    EMAIL_STATUS COUNT(*)

    ------------------------------ ----------

    Error 100

    Not Sent 300

    Sent 23770

  • 2007-12-2516www.oracleact.com

    SQL> drop index cust_order_idx;

    Index dropped.

    SQL> create index cust_order_idx on cust_order

    (decode(email_status,'Not Sent',1,'Error',2,NULL));

    Index created.

    SQL> analyze table cust_order compute statistics

    2 for table

    3 for all indexes

    4 for all indexed columns;

    Table analyzed.

    SQL> select table_name, index_name, num_rows, last_analyzed

    2 from user_indexes where table_name = 'CUST_ORDER' ;

    TABLE_NAME INDEX_NAME NUM_ROWS LAST_ANALYZED

    ------------ ----------------------- ---------- --------------------

    CUST_ORDER CUST_ORDER_IDX 400 18-FEB-2005 14:07:49

  • 2007-12-2517www.oracleact.com

    SQL> select count(*) from cust_order

    where decode(email_status,'Not Sent',1,'Error',2,NULL) = 2 ;

    COUNT(*)

    ----------

    100

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=17)

    1 0 SORT (AGGREGATE)

    2 1 INDEX (RANGE SCAN) OF 'CUST_ORDER_IDX' (NON-UNIQUE) (Cost=1 Card=100 Bytes

    SQL> select count(*) from cust_order

    where decode(email_status,'Not Sent',1,'Error',2,NULL) = 1 ;

    COUNT(*)

    ----------

    300

  • 2007-12-2518www.oracleact.com

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=17)

    1 0 SORT (AGGREGATE)

    2 1 INDEX (RANGE SCAN) OF 'CUST_ORDER_IDX' (NON-UNIQUE) (Cost=1 Card=300 Bytes

  • 2007-12-2519www.oracleact.com

    5. IOT - Index Organized Table

    Well suited for time interval data.

    CREATE TABLE COUNTRIES

    (

    COUNTRY_ID CHAR(2 BYTE) CONSTRAINT COUNTRY_ID_NN NOT NULL,

    COUNTRY_NAME VARCHAR2(40 BYTE),

    CURRENCY_NAME VARCHAR2(25 BYTE),

    CURRENCY_SYMBOL VARCHAR2(3 BYTE),

    REGION VARCHAR2(15 BYTE),

    CONSTRAINT COUNTRY_C_ID_PK PRIMARY KEY (COUNTRY_ID)

    )

    ORGANIZATION INDEX LOGGING

    TABLESPACE TAMIL_LARGE_DATA

    PCTFREE 10 INITRANS 2 MAXTRANS 255

    STORAGE ( INITIAL 16K NEXT 100M

    MINEXTENTS 1 MAXEXTENTS 2147483645

    PCTINCREASE 0 FREELISTS 1

    FREELIST GROUPS 1 BUFFER_POOL DEFAULT )

  • 2007-12-2520www.oracleact.com

    PCTTHRESHOLD 2

    INCLUDING COUNTRY_NAME

    OVERFLOW

    TABLESPACE USERS

    PCTUSED 40 PCTFREE 10 INITRANS 1 MAXTRANS 255

    STORAGE ( INITIAL 16K NEXT 100M

    MINEXTENTS 1 MAXEXTENTS 2147483645

    PCTINCREASE 0 FREELISTS 1

    FREELIST GROUPS 1 BUFFER_POOL DEFAULT )

    LOGGING

    NOPARALLEL;

    Note: PCTTHRESHOLD integer specifies percentage of space reserved

    in an IOT. Any portion of the row that exceeds the specified threshold

    is stored in the overflow area. PCTTHRESHOLD must be a value from

    1 to 50.

  • 2007-12-2521www.oracleact.com

    There are many benefits having a fact table defined as IOT. They are:

    1 The space used for PK is not required. Hence, multiple I/Os on Index and data are

    not required.

    2 Since most of the fact table has date (or time key) as the first column in the table

    as well as first column in the index, that is always used in the WHERE clause, that

    leads to speed of retrieving the data.

    3 IOTs can be partitioned

    Disadvantages are:

    1 Physical ROWID is NOT maintained on IOT. The table is left with only logical

    ROWID.

    In case of block corruption, and you want to extract maximum number of rows

    from the table, you have to use PK only, not the min or max of ROWID.

    2 PK constraint can not be dropped

    3 Unique constraints are not allowed

    4 Distribution and replication are not allowed

    Carefully evaluate the requirements, particularly ad hoc queries.

    If the table requires bit-mapped indexes on columns such as Male/Female, Status

    (Active/Inactive), YES/NO etc, then IOT is NOT a good choice.

    Also, be careful when you use INCLUDE CLAUSE AND OVERFLOW.

  • 2007-12-2522www.oracleact.com

    6. Using CONCATENATED INDEX

    Create concatenated index on multiple columns if all the columns

    (or some of the leading columns ) are used in the predicate.

    Myth: Always use most selective column as the first column in a concatenated

    index, so that Oracle will use the index in the query execution plan.

    Create index cust_idx on customer(last_name, first_name) ;

    7. Index Merges

    SQL> select * from t1

    where object_id between 1000 and 1020 and object_name like 'T%' ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=21 Card=1 Bytes=96)

    1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=21 Card=1 Bytes=96)

    2 1 INDEX (RANGE SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=2 Card=20)

  • 2007-12-2523www.oracleact.com

    SQL> select /*+ AND_EQUAL(T1, T1_IDX_1, T1_IDX_2) */ *

    from T1

    where object_id between 1000 and 1020 and object_name like 'T%' ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=21 Card=1 Bytes=96)

    1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=21 Card=1 Bytes=96)

    2 1 BITMAP CONVERSION (TO ROWIDS)

    3 2 BITMAP AND

    4 3 BITMAP CONVERSION (FROM ROWIDS)

    5 4 SORT (ORDER BY)

    6 5 INDEX (RANGE SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=2 Card=20)

    7 3 BITMAP CONVERSION (FROM ROWIDS)

    8 7 SORT (ORDER BY)

    9 8 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=2 Card=20)

  • 2007-12-2524www.oracleact.com

    8 Searching for Ranges

    SQL> desc ssn_region

    Name Null? Type

    -------------------------- -------- ------------------

    REG_ID NUMBER(38)

    REG_NAME VARCHAR2(20)

    LOW_SSN_NUM NUMBER(38)

    HIGH_SSN_NUM NUMBER(38)

    SQL> select min (low_ssn_num) , max(high_ssn_num), count(*) from ssn_region ;

    MIN(LOW_SSN_NUM) MAX(HIGH_SSN_NUM) COUNT(*)

    ---------------- ----------------- ----------

    101010001 101110000 10000

    Query -1

    select * from ssn_region

    where 101010998 between low_ssn_num and high_ssn_num

    Rows Row Source Operation

    ------- ---------------------------------------------------

    1 TABLE ACCESS BY INDEX ROWID OBJ#(68289)

    100 INDEX RANGE SCAN OBJ#(68293) (object id 68293) -- index used (SSN_REG_LOW)

  • 2007-12-2525www.oracleact.com

    Query -2

    select * from ssn_region

    where 701010998 between low_ssn_num and high_ssn_num ;

    Rows Row Source Operation

    ------- ---------------------------------------------------

    0 TABLE ACCESS BY INDEX ROWID OBJ#(68289)

    0 INDEX RANGE SCAN OBJ#(68294) (object id 68294) --- index used (SSN_REG_HIGH)

    Query -3 Dropped Index SSN_REG_HIGH

    select * from ssn_region

    where 701010998 between low_ssn_num and high_ssn_num

    call count cpu elapsed disk query current rows

    ------- ------ -------- ---------- ---------- ---------- ---------- ----------

    Parse 1 0.01 0.00 0 0 0 0

    Execute 1 0.00 0.00 0 0 0 0

    Fetch 1 0.02 0.03 45 47 0 0

    ------- ------ -------- ---------- ---------- ---------- ---------- ----------

    total 3 0.03 0.04 45 47 0 0

    Rows Row Source Operation

    ------- ---------------------------------------------------

    0 TABLE ACCESS FULL OBJ#(68289)

    Note: When the input value is not in the range, then Oracle chooses FULL table scan.

  • 2007-12-2526www.oracleact.com

    9 Queries Involving OR

    SQL> select * from t1

    where object_id = 800 or status = 'INVALID' or object_name = 'T1' ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=33 Card=243 Bytes=23328)

    1 0 TABLE ACCESS (FULL) OF 'T1' (Cost=33 Card=243 Bytes=23328))

    SQL> select * from t1 where object_id = 800 or object_name = 'T1' ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=3 Bytes=288)

    1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=3 Card=3 Bytes=288)

    2 1 BITMAP CONVERSION (TO ROWIDS)

    3 2 BITMAP OR

    4 3 BITMAP CONVERSION (FROM ROWIDS)

    5 4 INDEX (RANGE SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=1)

    6 3 BITMAP CONVERSION (FROM ROWIDS)

    7 6 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=1)

  • 2007-12-2527www.oracleact.com

    SQL> select /*+ USE_CONCAT */ *

    from t1 where object_id = 800 or object_name = 'T1' ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=5 Card=3 Bytes=288)

    1 0 CONCATENATION

    2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=2 Card=1 Bytes=96)

    3 2 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=1 Card=1)

    4 1 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=2 Card=1 Bytes=96)

    5 4 INDEX (RANGE SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=1 Card=1)

  • 2007-12-2528www.oracleact.com

    10 Inlist Iterator

    Query -1

    SQL> select * from t1

    where object_name IN ( 'T1', 'T1_IDX_1', 'T1_IDX_2' ) ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=6 Bytes=576)

    1 0 INLIST ITERATOR

    2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=7 Card=6 Bytes=576)

    3 2 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=2 Card=6)

  • 2007-12-2529www.oracleact.com

    10 Inlist Iterator . Contd

    Query 2

    SQL> select * from t1

    where object_name IN ( 'T1', 'T1_IDX_1', 'T1_IDX_2' ) or

    object_id between 69000 and 70000 ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=8 Card=7 Bytes=672)

    1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=8 Card=7 Bytes=672)

    2 1 BITMAP CONVERSION (TO ROWIDS)

    3 2 BITMAP OR

    4 3 BITMAP CONVERSION (FROM ROWIDS)

    5 4 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=1)

    6 3 BITMAP CONVERSION (FROM ROWIDS)

    7 6 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=1)

    8 3 BITMAP CONVERSION (FROM ROWIDS)

    9 8 INDEX (RANGE SCAN) OF 'T1_IDX_2' (NON-UNIQUE) (Cost=1)

    10 3 BITMAP CONVERSION (FROM ROWIDS)

    11 10 SORT (ORDER BY)

    12 11 INDEX (RANGE SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=2)

  • 2007-12-2530www.oracleact.com

    11 FAST_FULL INDEX SCAN

    Works best on the not null column if you want to count total number of rows.

    SQL> select /*+ INDEX_FFS(t1 t1_idx_1) */ count(*) from t1;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=1)

    1 0 SORT (AGGREGATE)

    2 1 INDEX (FAST FULL SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=7

    Card=23990)

    Parallel Fast Full Index Scan

    SQL> select /*+ INDEX_FFS(t1 t1_idx_1) parallel_index(t1 t1_idx_1 8) */

    count(*) from t1 ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=1)

    1 0 SORT (AGGREGATE)

    2 1 SORT* (AGGREGATE)

    3 2 INDEX* (FAST FULL SCAN) OF 'T1_IDX_1' (NON-UNIQUE) (Cost=7 Card=23990)

    2 PARALLEL_TO_SERIAL SELECT /*+ PIV_SSF */ SYS_OP_MSR(COUNT(*)) F

    3 PARALLEL_COMBINED_WITH_PARENT

  • 2007-12-2531www.oracleact.com

    13 Bind Variable and 5 Percent Guess

    SQL> create table t1 as select * from dba_objects ;

    Table created.

    SQL> desc t1

    Name Null? Type

    ------------------------- -------- ----------------------------

    OWNER VARCHAR2(30)

    OBJECT_NAME VARCHAR2(128)

    SUBOBJECT_NAME VARCHAR2(30)

    OBJECT_ID NUMBER

    DATA_OBJECT_ID NUMBER

    OBJECT_TYPE VARCHAR2(18)

    CREATED DATE

    LAST_DDL_TIME DATE

    TIMESTAMP VARCHAR2(19)

    STATUS VARCHAR2(7)

    TEMPORARY VARCHAR2(1)

    GENERATED VARCHAR2(1)

    SECONDARY VARCHAR2(1)

    SQL> var b1 varchar2(30);

    SQL> select * from t1

    where LAST_DDL_TIME > to_date(:b1, 'dd-mon-yyyy hh24:mi:ss') ;

  • 2007-12-2532www.oracleact.com

    12 Bind Variable and 5 Percent Guess . Contd..

    SQL> var b1 varchar2(30);

    SQL> select * from t1

    where LAST_DDL_TIME > to_date(:b1, 'dd-mon-yyyy hh24:mi:ss') ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE

    1 0 TABLE ACCESS (FULL) OF 'T1

    SQL> analyze table t1 compute statistics ;

    SQL> select * from t1

    where LAST_DDL_TIME > to_date(:b1, 'dd-mon-yyyy hh24:mi:ss') ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=33 Card=1200

    Bytes=103200)

    1 0 TABLE ACCESS (FULL) OF 'T1' (Cost=33 Card=1200 Bytes=103200)

    SQL> select count(*) from t1 ;

    COUNT(*)

    ----------

    23992

  • 2007-12-2533www.oracleact.com

    12 Bind Variable and 5 Percent Guess . Contd..

    SQL> select 23992*5/100 from dual;

    23992*5/100

    -----------

    1199.6 ----- Approximately equal to 1200 reported in the Cardinality

    Let us see when 2 bind variables are used

    SQL> var b2 varchar2(30) ;

    SQL> select * from t1

    where LAST_DDL_TIME > to_date(:b1, 'dd-mon-yyyy hh24:mi:ss') and

    LAST_DDL_TIME < to_date(:b2, 'dd-mon-yyyy hh24:mi:ss') ;

    Execution Plan

    ----------------------------------------------------------

    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=33 Card=60 Bytes=5160)

    1 0 FILTER

    2 1 TABLE ACCESS (FULL) OF 'T1' (Cost=33 Card=60 Bytes=5160)

    SQL> select 5*1200/100 from dual;

    5*1200/100

    ----------

    60 -- Same as reported in Card column

  • 2007-12-2534www.oracleact.com

    13 PCTFREE and PCTUSED

    PCTFREE 20 Minimum % of data block free and available for future update to the

    existing rows already within each block

    What it means that block allows row inserts until 80 ( = 100 -20) % is occupied.

    PCTUSED 40 The data segment is considered unavailable for the insertion of new

    rows until the amount of used space falls to 39 % or less (assuming that the

    blocks used space reached PCTFREE 80%)

    In short, PCTFREE parameter is for INSERT operation where as PCTUSED for

    DELETE operation.

    ROW CHAINING When data in a row is too large to fit into one data block, then

    Oracle allocates 2 or more data blocks for that row. This is called Row Migration.

    ROW MIGRATION A row that originally fit into one data block is updated so that the

    overall row length increases, and the block's free space is already completely

    filled. Oracle migrates the data for the entire row to a new data block, assuming

    the entire row can fit in a new block. Oracle preserves the original row piece of a

    migrated row to point to the new block containing the migrated row. The ROWID

    of a migrated row does not change.

  • 2007-12-2535www.oracleact.com

    13 PCTFREE and PCTUSED . Contd

    Minimize Records Per Block

    determines whether Oracle restricts the number of records (rows) that

    can be stored in a block

    In this way, we can restrict Oracle blocks to store fixed number of rows.

    Need not worry about future updates, row length increases etc

    SQL> create table my_table ( id number(7), name varchar2(30),

    some_text varchar2(1500) ) ;

    SQL> analyze table my_table compute statistics ;

    SQL> select object_id, data_object_id from dba_objects

    where object_name = 'MY_TABLE';

    OBJECT_ID DATA_OBJECT_ID

    ---------- --------------

    68357 68357

  • 2007-12-2536www.oracleact.com

    13 PCTFREE and PCTUSED . Contd

    Before You change the table definition,

    Login as sys account, run the below SQL

    SQL> select dataobj#, obj#, spare1

    2 from tab$

    3 where obj# = 68357 ;

    DATAOBJ# OBJ# SPARE1

    ---------- ---------- ----------

    68357 68357 736

    Note down the value of SPARE1 column.

  • 2007-12-2537www.oracleact.com

    13 PCTFREE and PCTUSED . Contd

    SQL> insert into my_table values (1, 'Tamil', rpad('x', 1500) ) ;

    SQL> insert into my_table values (2, 'Tandon', rpad('x', 1500) ) ;

    SQL> insert into my_table values (3, 'Selvan', rpad('x', 1500) ) ;

    SQL> insert into my_table values (4, 'Kannan', rpad('x', 1500) ) ;

    SQL> insert into my_table values (5, 'Ram', rpad('x', 1500) ) ;

    SQL> commit;

    SQL> select length(id), length(name), length(some_text) from my_table ;

    LENGTH(ID) LENGTH(NAME) LENGTH(SOME_TEXT)

    ---------- ------------ -----------------

    1 5 1500

    1 6 1500

    1 6 1500

    1 6 1500

    1 3 1500

    SQL> alter table MY_TABLE minimize records_per_block ;

  • 2007-12-2538www.oracleact.com

    13 PCTFREE and PCTUSED . Contd

    SQL> get x

    1 select dataobj#, obj#, spare1 , spare2, spare3, spare4, spare5

    2 from tab$

    3* where obj# = 68357

    4 /

    DATAOBJ# OBJ# SPARE1 SPARE2 SPARE3 SPARE4 SPARE5

    ---------- ---------- ---------- ---------- ---------- ---------- ----------

    68357 68357 32771

    Spare1 column value has been increased to 32771 from 736.

    SQL> truncate table my_table ;

    Table truncated.

  • 2007-12-2539www.oracleact.com

    13 PCTFREE and PCTUSED . Contd

    SQL> begin

    2 for K in 1 .. 8 loop

    3 insert into my_table values (K, 'name'||to_char(k), 'y') ;

    4 end loop ;

    5 end;

    6 /

    SQL> select dbms_rowid.rowid_relative_fno(rowid) filenum ,

    2 dbms_rowid.rowid_block_number(rowid) blocknum,

    3 id

    4 from my_table ;

    FILENUM BLOCKNUM ID

    ---------- ---------- ---------

    31 12810 1

    31 12810 2

    31 12810 3

    31 12810 4

    31 12811 5

    31 12811 6

    31 12811 7

    31 12811 8

    8 rows selected.

    W

    a

    tc

    h

    o

    u

    t th

    e

    B

    L

    O

    C

    K

    N

    U

    M

    B

    E

    R

    .

    O

    ra

    c

    le

    a

    llo

    c

    a

    te

    d

    4

    ro

    w

    s

    p

    e

    r b

    lo

    c

    k

    b

    a

    s

    e

    d

    o

    n

    o

    ld

    ro

    w

    le

    n

    g

    th

    .

  • 2007-12-2540www.oracleact.com

    13 PCTFREE and PCTUSED . Contd

    SQL> analyze table my_table compute statistics ;

    Table analyzed.

    SQL> select table_name, blocks, avg_row_len from user_tables

    2 where table_name = 'MY_TABLE' ;

    TABLE_NAME BLOCKS AVG_ROW_LEN

    ------------------------------ ---------- -----------

    MY_TABLE 2 14

  • 2007-12-2541www.oracleact.com

    Strategies To Speed Up Full Table Scan

    Decrease PCTFREE until row chaining or migration is not happening

    Increase PCTUSED so that deleted space will be reused immediately

    with high cost of FREELIST management

    Consider MINIMIZE RECORD PER BLOCK if you know the actual length

    of the rows after update

    Use Partitions Oracle will decide which partition to be used based on

    the predicate

    Use Parallel threads Oracle will determine the number of threads

    based on the resource available

    Store LONG / LOB columns in a separate TABLESPACE

    Use IOT if the table is always accessed via Primary Key

    Use CACHE option if the tables data are frequently accessed by many

    queries

    Use parallel degree on large tables in the create table statement

    Use separate memory pool for the tables that undergo full table scan

    operation

    Use HASH Cluster if the table is static

    Use FULL and PARALLEL Hints in the Query, if its appropriate

    Increase DB_FILE_MULTIBLOCK_READ_COUNT value

  • 2007-12-2542www.oracleact.com

    14 UPDATE Statement Old Method

    SQL> select * from emp2 ;

    EMPID BONUS

    ---------- ----------

    1001 101

    1002 102

    1003 103

    SQL> select * from new_bonus;

    EMPID BONUS

    ---------- ----------

    1001 501

    1003 502

    1 update emp2 a

    2 set bonus = (select bonus

    3 from new_bonus b

    4 where b.empid = a.empid)

    5 where exists (select null

    6 from new_bonus b

    7* where b.empid = a.empid)

    SQL> /

    2 rows updated.

    SQL> select * from emp2 ;

    EMPID BONUS

    ---------- ----------

    1001 501

    1002 102

    1003 502

  • 2007-12-2543www.oracleact.com

    UPDATE Statement New Method -1

    SQL> select * from emp2 ;

    EMPID BONUS

    ---------- ----------

    1001 101

    1002 102

    1003 103

    SQL> select * from new_bonus;

    EMPID BONUS

    ---------- ----------

    1001 501

    1003 502

    SQL> update emp2 a set

    2 a.bonus = coalesce (

    3 (select b.bonus

    4 from new_bonus b

    5 where b.empid = a.empid),

    6 a.bonus) ;

    3 rows updated.

    SQL> commit;

    Commit complete.

    SQL> select * from emp2 ;

    EMPID BONUS

    ---------- ----------

    1001 501

    1002 102

    1003 502

  • 2007-12-2544www.oracleact.com

    UPDATE Statement New Method -2

    SQL> select * from emp2 ;

    EMPID BONUS

    ---------- ----------

    1001 101

    1002 102

    1003 103

    SQL> select * from new_bonus;

    EMPID BONUS

    ---------- ----------

    1001 501

    1003 502

    SQL> update (select a.bonus old_value ,

    2 b.bonus new_value

    3 from emp2 a , new_bonus b

    4 where a.empid = b.empid)

    5* set old_value = new_value

    SQL> /

    set old_value = new_value

    *

    ERROR at line 5:

    ORA-01779: cannot modify a column which maps

    to a non key-preserved table

    SQL> alter table emp2 add constraint emp2_uq unique

    (empid) ;

    Table altered.

    SQL> alter table new_bonus add constraint nb_uq

    unique (empid) ;

    Table altered.

    SQL> update (select a.bonus old_value ,

    2 b.bonus new_value

    3 from emp2 a , new_bonus b

    4 where a.empid = b.empid)

    5* set old_value = new_value

    SQL> /

    2 rows updated.

    SQL> select * from emp2;

    EMPID BONUS

    ---------- ----------

    1001 501

    1002 102

    1003 502

  • 2007-12-2545www.oracleact.com

    Oracle Performance Tuning Class - 1

    I value your questions, comments and suggestions.

    Please send your comment to [email protected].

    Beacon Infotech Corporation.

    Web: www.oracleact.com