2713894 oracle tuning tips

Upload: nst-tnagar

Post on 04-Apr-2018

245 views

Category:

Documents


1 download

TRANSCRIPT

  • 7/30/2019 2713894 Oracle Tuning Tips

    1/41

    1

    SQL Performance Tuning Tips

    By Puneet Goenka

  • 7/30/2019 2713894 Oracle Tuning Tips

    2/41

    2

    Tuning Tips and Techniques

    Oracles SQL is a very flexible language.

    You can use many different SQL statements

    to accomplish the same purpose. Yet, although dozens of differently

    constructed queries and retrieval statements

    can produce the same result, in a given

    situation only one statement will be the most

    efficient choice.

  • 7/30/2019 2713894 Oracle Tuning Tips

    3/41

    3

    It is much harder to write efficient SQL than it is towrite functionally correct SQL

    A SQL choice is correct only if it produces the right

    result in the shortest possible amount of time,without impeding the performance of any other

    system resources.

  • 7/30/2019 2713894 Oracle Tuning Tips

    4/41

    4

    Sharing SQL Statements

    Parsing a SQL statement and figuring out itsoptimal execution plan are time-consumingoperations, Oracle holds SQL statements in

    memory after it has parsed them Whenever you issue a SQL statement,

    Oracle first looks in the context (SGA) area tosee if there is an identical statement there

    To be shared, the SQL statements must trulybe the same

  • 7/30/2019 2713894 Oracle Tuning Tips

    5/41

    5

    For example the following two select statements are NOT the same:

    SELECT STUDENT_NMBER,NAMEFROM STUDENTWHERE STUDEN_NUMBER = 0220

    Select Student_Number,NameFrom StudentWhere Student_Number = 0220

  • 7/30/2019 2713894 Oracle Tuning Tips

    6/41

    6

    Using Bind variables when possible Try using Bind Variable instead of Literals. Consider the following

    SQL statementSELECT FIRST_NAME, LAST_NAMEFROM ClientWHERE CLIENT_NUM = 1200

    Since the CLIENT_NUMBER is likely to be different for everyexecution, we will almost never find a matching statement in theShared Pool and consequently the statement will have to be reparsed

    every time Consider the following approach

    SELECT FIRST_NAME, LAST_NAME

    FROM Client

    WHERE CLIENT_NUM = :Client_Num

    You do not need to create a new cursor or re-parse the SQL statement if thevalue of the bind variable changes. Also, if another session executes the samestatement, it is likely to find them in the Shared Pool, since the name of thebind variable does not change from execution to execution.

  • 7/30/2019 2713894 Oracle Tuning Tips

    7/41

    7

    Using ROWID When Possible

    Each record added to the database has a unique ROWID and will

    never change until the delete statement issued on that record. If the record block or location was changed for any reason, the

    original ROWID points to the new location or the new ROWID and so

    on. Use ROWID whenever possible to get the best performance out of

    your retrievals

  • 7/30/2019 2713894 Oracle Tuning Tips

    8/41

    8

    cursor accounts_cur isselect acct_no,

    currency,branchRowid acct_rowid,

    From account

    where . . . .

    for acct_rec in accounts_cur loop

    update account set

    where rowid = acct_rec.acct_rowid;

    end loop;

  • 7/30/2019 2713894 Oracle Tuning Tips

    9/41

    9

    Using WHERE in Place of HAVING

    In general, avoid including a HAVING clause in the SELECT

    statements. The HAVING clause filters selected rows only after allrows have been fetched. This could include sorting, summing, andetc. HAVING clause

    usually used to filter a SELECT statement containing groupfunctions.

    select *from accountwhere cust_Active_flag = yhaving group = 001

    Instead use -

    select *from accountwhere cust_Active_flag = yand group = 001

  • 7/30/2019 2713894 Oracle Tuning Tips

    10/41

    10

    Using UNION ALL instead of UNION

    The SORT operation is very expensive in terms of

    CPU consumption.

    The UNION operation sorts the result set to eliminate

    any rows, which are within the sub-queries.

    UNION ALL includes duplicate rows and does not

    require a sort. Unless you require that these duplicate

    rows be eliminated, use UNION ALL

  • 7/30/2019 2713894 Oracle Tuning Tips

    11/41

    11

    Using NOT EXISTS in place of NOT IN for indexed

    columns In sub-query statements such as the following, the NOT IN

    clause causes an internal sort/merge.

    select * from Studentwhere STUDENT_NUM not in

    (select STUDENT_NUM from CLASS) So use-

    select * from STUDENT Cwhere not exists(select 1 from CLASS A where

    A.STUDENT_NUM = C.STUDENT_NUM)

  • 7/30/2019 2713894 Oracle Tuning Tips

    12/41

    12

    Using IN with MINUS in place of NOT IN for non

    indexed columns

    In sub-query statements such as the following, the NOT IN clause

    causes an internal sort/merge

    select * from system_userwhere su_user_id not in(select ac_user from account)

    INSTEAD USE

    select * from system_userwhere su_user_id in(select su_user_id from system_user

    minus

    select ac_user from account)

  • 7/30/2019 2713894 Oracle Tuning Tips

    13/41

    13

    Using Joints in Place of EXISTS for Unique Scan Indexes and

    small tables

    In general join tables rather than specifying sub-queries for them suchas the following:

    select acct_ID, currency, branchfrom accountwhere exists (select 1 from branch where code =branch and def_curr = '001')

    With join -

    select acct_ID,currency, branchfrom account A, branch Bwhere b.code = A.branchand A.def_curr = '001'

  • 7/30/2019 2713894 Oracle Tuning Tips

    14/41

    14

    Influencing the Optimizer using HINTS

    Hints are special instructions to Optimizer. You can change theOptimization goal for an individual statement by using Hint. Somecommonly used Hints are: CHOOSE, RULE, FULL(table_name),

    INDEX(table_name index_name), USE_NL,USE_HASH(table_name), PARALLEL(table_name parallelism) etc.

    SELECT /*+RULE*/ NAME,

    ACCT_ALLOCATION_PERCENTAGEFROM ACCOUNTS WHERE ACCOUNT_ID = 1200

    The above SQL statement will be processed using the RULE basedoptimizer.

    SELECT /*+ INDEX(A, ACCT_ID_IND) */ NAME,

    ACCT_ALLOCATION_PERCENTAGEFROM ACCOUNTS AWHERE ACCOUNT_ID = :ACCT_ID ANDCLIENT_ID= :CLIENT_ID

    In the above SQL statement, an Index Hint has been used to forcethe use of a particular index.

  • 7/30/2019 2713894 Oracle Tuning Tips

    15/41

    15

    Using Indexes to Improve Performance Indexes primarily exist to enhance performance. But they do

    not come without a cost. Indexes must be updated duringINSERT, UPDATE and DELETE operation, which may slowdown performance

    Besides, the usefulness of an Index depends on selectivity of a

    column/columns. Generally Indexes are more selective if the column/columns

    have a large number of unique values.

    If an Index contains more than one column, it is calledCONCATENATED INDEX .

    Concatenated index is often more selective than a single keyindex.

    Column positions play an important role in Concatenatedindex. While using Concatenated Index, be sure to useLEADING columns

  • 7/30/2019 2713894 Oracle Tuning Tips

    16/41

    16

    Which is Faster: Indexed Retrieval or Full-table

    Scan? Full-table scans can be efficient because they require little disk

    movement. The disk starts reading at one point and continues reading

    contiguous data blocks.

    Index retrievals are usually more efficient when retrieving few recordsor when using joints with other tables.

    If more than 52%, this percentage defers from table to table anddepends on the physical I/O, of the table retrieved a full table scan isbetter.

  • 7/30/2019 2713894 Oracle Tuning Tips

    17/41

    17

    Avoiding Calculations on Indexed Columns The optimizer does not use an index if the indexed column is a part of

    a function (in the WHERE clause). In general, avoid doing

    calculations on indexed columns, apply function and concatenating on

    an indexed columns.

    Select * from

    AccountWhere substr(ac_acct_no,1,1) = 1

    Instead use -

    Select * fromAccountWhere ac_acct_no like 1%

    Note: The SQL functions MIN and MAX are exceptions tothis rule and will utilize all available indexes.

  • 7/30/2019 2713894 Oracle Tuning Tips

    18/41

    18

    Avoiding NOT on Indexed Columns

    In general avoid using NOT when testing indexed columns.

    When Oracle encounters a NOT, it will choose not to use index andwill perform a full-table scan instead.

    Remember, indexes are built on what is in a table, but not what isNOT in a table.

    For example the following select statement will never use the index onSTUDENT_NUM column

    Select * from

    studentWhere STUDENT_NUM not like 9%

  • 7/30/2019 2713894 Oracle Tuning Tips

    19/41

    19

    Using UNION in Place of OR

    In general, always consider the UNION verb instead of OR verb in the

    WHERE clauses.

    Using OR on an indexed column causes the optimizer to perform a

    full-table scan rather than an indexed retrieval.

  • 7/30/2019 2713894 Oracle Tuning Tips

    20/41

    20

    Position of Joins in the WHERE Clause

    Table joins should be written first before any condition of WHERE clause.

    And the conditions which filter out the maximum records should be placed at

    the end after the joins as the parsing is done from BOTTOM to TOP.

    Least Efficient :

    SELECT . . . .

    FROM EMP E

    WHERE SAL > 50000

    AND JOB = CLERKAND 25 < (SELECT COUNT(*)

    FROM EMP WHERE MGR = E.EMPNO);

  • 7/30/2019 2713894 Oracle Tuning Tips

    21/41

    21

    Most Efficient :

    SELECT . . . .

    FROM EMP E

    WHERE 25 < (SELECT COUNT(*)FROM EMP

    WHERE MGR = E.EMPNO )

    AND SAL > 50000 AND JOB =

    CLERK;

  • 7/30/2019 2713894 Oracle Tuning Tips

    22/41

    22

    Nested Loops Join Sort-Merge Join Hash Join ClusterJoin

    When can be used: Any join Equi joins only Equi joins only Equijoins on

    complete

    cluster key of

    clustered

    tables only

    Optimizer hint: use_nl Use_merge use_hash None

    Resource concerns: CPU Temporary segments Memory Storage Disk I/O

    init.ora parameters:None sort_area_size hash_join_enabledNone db_file_multi block_

    hash_area_sizeread_count hash_multiblock_io_count

    Features:Works with any join Better than nested Better than nested ReducesI/O for master-

    loop when indesx is loop when index is

    detail Queries

    missing or search missing or search

    critiria is not restrictive criteria is not restrictive

    Side by Side Comparison of Join Methods

  • 7/30/2019 2713894 Oracle Tuning Tips

    23/41

    23

    ORACLE parser always processes table names from right to left, sothe table name you specify last (driving table) is actually the firsttable processed.

    If you specify more than one table in a FROM clause of a SELECT

    statement, you must choose the table containing the lowest number ofrows as the driving table.

    When ORACLE processes multiple tables, it uses an internalsort/merge procedure to join those tables.

    First, it scans and sorts the first table (the one specified last in theFROM clause).

    Next, it scans the second table (the one prior to the last in the FROMclause) and merges all of the rows retrieved from the second tablewith those retrieved from the first table.

    For example:

    Table TABA has 16,384 rows.

    Table TABB has 1 row.

    SELECT COUNT(*) FROM TABA, TABB 0.96 seconds elapsedSELECT COUNT(*) FROM TABB, TABA 26.09 seconds elapsed

  • 7/30/2019 2713894 Oracle Tuning Tips

    24/41

    24

    If three tables are being joined, select the intersection table as the drivingtable.

    The intersection table is the table that has many tables dependent on it.

    E.g.. The EMP table represents the intersection between the LOCATION

    table and the CATEGORY table.SELECT . . .

    FROM LOCATION L, CATEGORY C, EMP E

    WHERE E.EMP_NO BETWEEN 1000 AND 2000

    AND E.CAT_NO = C.CAT_NO

    AND E.LOCN = L.LOCNis more efficient than this next example:

    SELECT . . .

    FROM EMP E,

    LOCATION L, CATEGORY C

    WHERE E.CAT_NO = C.CAT_NO

    AND E.LOCN = L.LOCN

    AND E.EMP_NO BETWEEN 1000 AND 2000

  • 7/30/2019 2713894 Oracle Tuning Tips

    25/41

    25

    Problems when Converting Index Column Types

    Oracle performs simple column type conversion, or casting,

    when it compares columns of different type. If a numeric

    column is compared to an alphabetic column, the charactercolumn automatically has its type converted to numeric.

    Select *from AccountWhere ACCOUNT_ID = 90426001

    In fact, because of conversion this statement will actually be processedas:

    Select *

    from AccountWhere to_number(ACCOUNT_ID) = 90426001

  • 7/30/2019 2713894 Oracle Tuning Tips

    26/41

    26

    But the following statement:

    Select *

    From acc_txnWhere acc_txn_ref_no = 119990012890

    Will be processed as:

    Select *From acc_txn

    Where acc_txn_ref_no = to_number(119990012890 )

  • 7/30/2019 2713894 Oracle Tuning Tips

    27/41

    27

    Use DECODE to Reduce Processing

    The DECODE statement provides a way to avoid having toscan the same rows repetitively or to join the same tablerepetitively.

    For example:

    SELECT COUNT(*), SUM(SAL)

    FROM EMP

    WHERE DEPT_NO = 0020

    AND ENAME LIKE SMITH%;

    SELECT COUNT(*), SUM(SAL)

    FROM EMP

    WHERE DEPT_NO = 0030

    AND ENAME LIKE SMITH%;

    You can achieve the same result much more efficiently withDECODE:

  • 7/30/2019 2713894 Oracle Tuning Tips

    28/41

    28

    SELECT COUNT(DECODE(DEPT_NO,0020, X, NULL))

    D0020_COUNT,

    COUNT(DECODE(DEPT_NO,0030,X,NULL))D0030_COUNT,

    SUM(DECODE(DEPT_NO,0020, SAL, NULL))

    D0020_SAL,

    SUM(DECODE(DEPT_NO, 0030, SAL, NULL))

    D0030_SALFROM EMP

    WHERE ENAME LIKE SMITH%;

    Similarly, DECODE can be used in GROUP BY or ORDER

    BY clause effectively.

  • 7/30/2019 2713894 Oracle Tuning Tips

    29/41

    29

    To improve performance, minimize the number of tablelookups in queries, particularly if your statements includesub-query SELECTs or multi-column UPDATEs.

    For example:

    Least Efficient :

    SELECT TAB_NAME

    FROM TABLES

    WHERE

    TAB_NAME =(SELECT TAB_NAME

    FROM TAB_COLUMNS

    WHERE VERSION = 604)

    AND

    DB_VER = (SELECT DB_VER

    FROM TAB_COLUMNS

    WHERE VERSION = 604)

  • 7/30/2019 2713894 Oracle Tuning Tips

    30/41

    30

    Most Efficient :

    SELECT TAB_NAME

    FROM TABLES

    WHERE (TAB_NAME,DB_VER)=

    (SELECT TAB_NAME, DB_VER

    FROM TAB_COLUMNS

    WHERE VERSION = 604)

    U EXISTS i Pl f DISTINCT

  • 7/30/2019 2713894 Oracle Tuning Tips

    31/41

    31

    Use EXISTS in Place of DISTINCT

    Avoid joins that require the DISTINCT qualifier on theSELECT list when you submit queries used to determineinformation at the owner end of a one-to-many relationship

    (e.g. departments that have many employees).

    Least Efficient :

    SELECT DISTINCT DEPT_NO, DEPT_NAME

    FROM DEPT D, EMP E

    WHERE D.DEPT_NO = E.DEPT_NO

    Most Efficient :

    SELECT DEPT_NO, DEPT_NAME

    FROM DEPT D

    WHERE EXISTS (SELECT X

    FROM EMP E

    WHERE E.DEPT_NO = D.DEPT_NO);

    EXISTS is a faster alternative because the RDBMS kernelrealizes that when the sub-query has been satisfied once,the query can be terminated.

  • 7/30/2019 2713894 Oracle Tuning Tips

    32/41

    32

    Some Dos and Donts

    Some SELECT statement WHERE clauses do not use indexes

    at all. If you have specified an index over a table that is

    referenced by a clause of type shown in this section Oracle will

    simply ignore the index.

    For each clause that cannot use an index, an alternative

    approach, which will allow you to get better performance out of

    your SELECT statements is suggested.

  • 7/30/2019 2713894 Oracle Tuning Tips

    33/41

    33

    Do Not Use:Select * from

    AccountWhere substr(ac_acct_no,1,1) = 9

    Use:

    Select * fromAccountWhere ac_acct_no like 9%

    Do Not Use:

    Select *

    From fin_trxnWhere ft_trxn_ref_no != 0

    Use: Select *

    From fin_trxnWhere ft_trxn_ref_no > 0

    Do Not Use:

  • 7/30/2019 2713894 Oracle Tuning Tips

    34/41

    34

    Do Not Use:Select *From accountWhere ac_type || ac_branch = sav001

    Use:Select *From accountWhere ac_type = sav

    And ac_branch = sav001

    Do Not Use:Select *

    From CLIENT where

    to_char(CUTT_OFF_TIME,yyyymmdd) =to_char(sysdate,yyyymmdd)

    Use:Select *

    From CLIENTWhere CUT_OFF_DATE >=

    trunc(sysdate) and CUT_OFF_TIME to_char(sysdate,yyyymmdd)

    Use:

    Select *

    From acct_trxnWhere at_value_date >= trunc(sysdate) + 1

  • 7/30/2019 2713894 Oracle Tuning Tips

    36/41

    36

    Do Not Use:Select *From acct_trxnWhere to_char(at_value_date,yyyymmdd) =to_char(sysdate,yyyymmdd)

    Use:

    Select *

    From acct_trxnWhere at_value_date >= trunc(sysdate)

  • 7/30/2019 2713894 Oracle Tuning Tips

    38/41

    38

    Do Not Use:Select *

    From acct_trxn

    Where to_char(at_value_date,yyyymmdd)

  • 7/30/2019 2713894 Oracle Tuning Tips

    39/41

    39

    Avoid Using SELECT * Clauses

    The dynamic SQL column reference (*) gives you a way to refer toall of the columns of a table.

    Do not use the * feature because it is very inefficient -- the * has to

    be converted to each column in turn.

    The SQL parser handles all the field references by obtaining the

    names of valid columns from the data dictionary and substitutes them

    on the command line, which is time consuming.

    Using SQL*Plus Autotrace

  • 7/30/2019 2713894 Oracle Tuning Tips

    40/41

    40

    g

    If youre using SQL*Plus you can take advantage of the auto tracefeature to have queries explained automatically.

    SQL*Plus will execute the query and display the execution plan following

    the results.

    E.g

    SQL> SET AUTOTRACE ON EXPLAINSQL> SELECT animal_name FROM aquatic_animal

    ORDER BY animal_name;ANIMAL_NAME

    ------------------------------Batty

    Bopper

    Flipper

    3 rows selected.

    Execution Plan

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

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

    1 0 SORT (ORDER BY) (Cost=3 Card=10 Bytes=170)

    2 1 TABLE ACCESS (FULL) OF AQUATIC_ANIMAL (Cost=1 Card=10Bytes=170)

  • 7/30/2019 2713894 Oracle Tuning Tips

    41/41

    41

    SQL*Plus does execute the query. If a query generates a lot of I/O andconsumes a lot of CPU, you wont want to kick it off just to see the

    execution plan.

    In that case use following :

    SQL> SET AUTOTRACE TRACEONLY EXPLAIN

    you are through using autotrace, you can turn the feature off by issuing the

    SET AUTOTRACE OFF command.