APPLICATION TUNING This document is meant to explain the points to be considered, while formulating your SQL’s.
Before tuning your SQL you should understand the oracle memory structure and different phases of SQL query processing. Memory Structure System Global Area DB buffer Log buffer Sharedpool Library cache Private sql area Persistent area Run time area Data dictionary cache
Shared sql area
Whatever the operation we are performing, everything will be handled only through the Random Access Memory. Oracle also does its process through memory by allocating a separate area for its access called SGA. Of course, apart from this SGA, oracle allocates Sort area, Software Code area, & Program Global area(PGA). One of the important factors of the database operation is the DB buffer cache, and this buffer cache is made up of memory blocks of the same size of Oracle’s blocks. Since, all the data stored in terms of blocks in the physical data files can be manipulated only in the DB buffer cache. The buffers stored in the database buffer cache can be classified as : - Dirty buffers: are those buffers, which hold data, touched by transaction. - Pinned buffers: are those buffers, which are being modified by transaction. - Free buffers: are those buffers, which are used to hold data from datafile. DB buffer cache contains two lists called - LRU (Least Recently Used list) - MRU (Most Recently Used list) Whenever an oracle user process accesses a piece of data, it has to copy data from disk to the buffer, before accessing it. This is called cache miss, whom we should avoid as much as possible to increase the query performance. A cache hit is nothing but when a process access a piece of data that is already in the cache, the process can read the data directly from memory. Normally a cache hit is faster than, cache miss because the data is read from the memory instead of disk.
Log Buffers: For a single atomic change made to the database by insert, update, delete, create, alter or drop operations, server process creates redo entries to reconstruct, or redo the changes made. And these redo entries for each and every transactions are stored in the log buffer cache which is circular buffer in the SGA. Shared Pool: The shared pool contains two parts 1. Data dictionary cache. Oracle accesses the data dictionary frequently during the process of SQL statements. Since the data dictionary is accessed so often by Oracle, it allocates one special area called data dictionary cache. The data dictionary caches are shared by all Oracle user process. 2. Library cache: It contained two main areas called. a. Shared SQL area, which contains the parsed representation (Parse tree) of the SQL statements fired by the user and the cursors in the Shared SQL area are maintained by LRU algorithm. Whenever the user fires a SQL statement, Oracle checks the shared pool to see if a shared SQL area already exists for an identical statement. If there is already a shared SQL area for the statement, it’s used for the execution of the subsequent new instances of the statement. In case, if there is not a shared SQL area for a statement, Oracle allocates a new cursor in the shared SQL area after it’s getting parsed in the user’s Pvt. SQL area. b. Private SQL area, is a memory area that contains data such as bind information and runtime buffers. Each session that issues a SQL statement has a private SQL area. It can be classified as persistent area & Run time area. The persistent area contains bind information that persists across executions, code for data type conversion, and other state information. The Runtime area contains information used while the SQL statement is being executed. 5 phases of processing the SQL query: 1) Open 2) Parse 3) Fetch 4) Execute 5) Close In Open phase, one cursor area (context area) will be opened for your query In Parse phase, the following processes will take place i) SQL statement is verified, whether valid or not (Syntax checking). ii) The tables, columns and privileges are verified (Symantec checking) iii) A Parse tree is prepared, based on the execution plan iv) The parse tree into SQL area (reuse to identical query).
your query will never use that index when you write a query with following conditions.
Approach to tune SQL:
I. c. Don’t index columns that do not have many unique values (poor selectivity). Remove non-selective indexes to speed up insert/update/delete. d. g. b. Consider composite index for better selectivity and additional data storage f. you can very well consider function-based indexes. e. A function-based index is an index on an expression. Points to be noted: 1. rows are selected from the corresponding data files and put into the data block buffer. by server process. Columns that have unique values are excellent candidates for indexing. Restructure the Index. Oracle automatically indexes on unique/primary key fields. col1 > col2 col1 < col2 col1 >= col2 col1 <= col2 Where Col1 is not null Where Col1 is null Where Col1 not in Where col1!=<expr> Where col1 like ‘% pattern’ l. col1 and col2 are in the same table. If you are using oracle 8i. Even though you are having indexes. a. In Close phase the opened cursor will be closed and temporary memory will be released. In this case. user process sends the records to the corresponding users. b. Oracle strongly recommends
. f. In Execute phase. Consider hash cluster for uniqueness data d. Frequently modified columns probably should not be indexed fields because of the overhead involved in updating/inserting/deleting. Frequently accessed columns in SELECT clause can most benefit from indexes. Consider Bit-map index for low cardinal fields like SEX. Use the following guide lines to decide which columns to be indexed: a. Consider Index cluster.In Fetch phase. Columns in which a good percentage of rows are duplicates can not take advantage of indexes. consider bitmap indexes on poor selectivity fields or consider composite index to improve the selectivity. e. Index performance-critical access path c. Columns that are commonly used in Joins are good candidates for index. Choose columns that are most frequently specified in WHERE clauses.
DEPTNO and etc. don’t use expressions.using function-based indexes whenever possible. if you are not using wildcards. wherever Possible. When you write conditions those compare columns with constants. While using LIKE operator. is fast. WHERE dno IN (10. the query optimizer
. Eg: Sal>(24000/12) – Not optimized Sal >2000 – Optimized b. then don’t use LIKE. c. While creating indexes on a table if you have created a composite index on columns (A. Restructure the SQL Statements. is slow because of data dictionary hit. a. i. . Select count (*) from emp.Here index will perform for range scan.30) dno=10 OR dno=20 OR dno=30 – Not optimized – Optimized. b. But if you know the full string. Use equality operator instead. desig Like ‘DBA’ – Not optimized desig=’DBA’ – Optimized desig like ‘DB%’ – Correct. better to use it. When the number of condition in IN operator is less.B) and a separate index exists on the column A then the second index is not really required as the first index will suffice for queries using on the column A in the search condition. When you use ANY or ALL or BETWEEN operators. Example: create index idx on emp (upper (empname)). Indexing does improve performance for querying but is an overhead when inserting and updating.
d . a. Select * from emp where upper (empname)=’MARK’.20. h. Oracle strongly recommends Bitmap Index on less selectivity fields like SEX. Eg. Select count (rowid) from emp. As a thumb rule never index more than 50% of the columns of a given table as in this cases using the index might be slower than a full table scan. The performance degrade due to excessive indexes is more apparent in OLTP databases and also during batch loads. use OR and = operator Eg. II.
dno FROM dept WHERE dno NOT IN (SELECT dno from emp). If your WHERE conditions have more OR operators.)
.6000) – Not optimized Where sal >5000 AND sal>6000 – Optimized Eg3. – Optimized (Make sure ‘custno’ column is the primary key or indexed. Eg. Eg.expands the condition .dno).dno=emp. Try to avoid IN/NOT IN and use EXISTS/NOT EXISTS SELECT dname.* FROM accounts.) h. it’s better that you expand the condition as far as possible using OR operator .1 Where Sal=ANY(5000. . (Make sure you are having INDEX) – Optimized g. – Not optimized SELECT * FROM emp WHERE job = 'CLERK' UNION ALL SELECT * FROM emp WHERE deptno = 10 AND job <> 'CLERK'. Eg. Use <> or != or ^= relational operators instead. NOT dno = (SELECT dno FROM emp WHERE ename = 'TAYLOR') – Not optimized deptno <> (SELECT deptno FROM emp WHERE ename = 'TAYLOR') – Optimized f.So. Try to avoid using the NOT logical operator as far as possible. SELECT * FROM accounts WHERE custno IN (SELECT custno FROM customers).custno. – Not optimized SELECT accounts. Where sal BETWEEN 2000 AND 5000 – Not optimized Where sal >=2000 AND sal<=5000 – Optimized e.6000) – Not optimized Where sal=5000 OR sal=6000 – Optimized Eg2. customers WHERE accounts.dno FROM dept WHERE dno NOT EXISTS (SELECT dno FROM emp WHERE dept.Not Optimized SELECT dname.custno = customers. then you have to rewrite the query with SET operators because SET operators execute more efficiently then OR (Relational Operators). . Complex queries have to be changed to join. Where sal >ALL(5000.Optimized (Make sure the dno on emp is Indexed. SELECT * FROM emp WHERE job = 'CLERK' OR deptno = 10. Eg.
linked by the AND verb in a bottom-up fashion. Create view to reduce the cost of QUERY PARSING for complex queries. j. put directly on to the tables.
Using Efficient Non-index WHERE clause sequencing.
Example: SELECT …………… Total CPU time: 156.6 seconds FROM emp E WHERE 25 AND AND Total CPU time:
< ( SELECT COUNT(*) FROM emp WHERE emp_mgr = E. Example: SELECT ……………………… seconds Total CPU time: 28. linked by the OR verb in a top-down fashion. and if it is found false. the second clause is then tested. This means that the first clause (first in the OR list) is evaluated. Always try to position the most expensive OR clause last in the WHERE clause sequencing. and if it is found true. Always try to position the most expensive clause first in the WHERE clause sequencing.
m. This means that the first clause (last in the AND list) is evaluated.emp_no ) emp_salary > 50000 emp_type = ‘MANAGER’
Oracle evaluates un-indexed equations. Minimize the Distinct using NOT IN instead of IN. the second clause is then tested. But don’t recycle views ie selecting value from view unnecessarily l. Outer join is always problematic. k.emp_no ) Simply alter the order of the AND clauses: SELECT …………… 10.i. So don’t put outer join query on join views.3 seconds FROM emp E WHERE emp_salary > 50000 AND emp_type = ‘MANAGER’ AND 25 < ( SELECT COUNT(*) FROM emp WHERE emp_mgr = E.3
. of database calls.
Oracle evaluates un-indexed equations. Use INSERT/DELETE/UPDATE RETURNING in PL/sql to reduce the no.
FROM emp E WHERE (emp_salary > 50000 AND emp_type = ‘MANAGER’) OR 25 < ( SELECT COUNT(*) FROM emp WHERE emp_mgr = E. 2.6 seconds FROM emp E WHERE 25 < ( SELECT COUNT(*) FROM emp WHERE emp_mgr = E. variables bound and the data block read.emp_no) OR ( emp_salary > 50000 AND emp_type = ‘MANAGER’ ) 1.
. …………………….emp_no )
Simply alter the order of the OR clauses: SELECT …………………… Total CPU time: 101. the statement needs to be parsed.emp_no = 56722 FOR UPDATE. Reducing the physical number of trips to the database is particularly beneficial in Client-Server configurations in which the database may need to be accessed over a network. indexes evaluated. ………………………… INTO :emp_rowid. Using ROWID When Possible
The ROWID of a record is the fastest method of record retrieval. UPDATE emp SET emp. The performance can be improved by selecting a record before updating or deleting it and including ROWID in the initial selection list..
Example: SELECT ROWID. Oracle needs to perform many internal processing steps. FROM emp WHERE emp.name = …………………………… WHERE ROWID = :emp_rowid. Reducing the Number of Trips to the Database Every time a SQL statement is executed.
The following examples show three distinct ways of retrieving data about employees who have employee numbers 0342 or 0291.emp_no = 0291. salary.
METHOD 1 shows two separate database accesses :
SELECT emp_name. C1 (342). salary.emp_no = 0342 B. 3.grade emp A. A. A and B. grade FROM emp WHERE emp_no = 0291. C1 (E_no number) IS emp_name. B.
END. SELECT emp_name. A. C1 (291).emp_name. B.
In the above method. B. salary.salary. the same table is identified by two aliases. grade FROM emp WHERE emp_no = 0342. C1 INTO ……………………………….emp_name.grade. that are joined by a single statement. the records will be rejected. In this way. C1 INTO ………………………………. grade emp emp_no = E_no.
METHOD 2 shows the use of one cursor and two fetches: DECLARE CURSOR SELECT FROM WHERE OPEN FETCH ………………… ………………… OPEN FETCH CLOSE C1. emp B A. If the comparison is performed. Oracle uses only one cursor and performs only one fetch. Using NULL values: Programmers should never directly compare null to anything else.
METHOD 3 shows a SQL table join: SELECT FROM WHERE And A.salary.
Using DECODE in ORDER BY and GROUP BY clauses
0020. each with a different ORDER BY clause. ‘Y’). SELECT ‘X’ FROM DUAL WHERE ‘X’ = NVL(NULL. salary. COUNT(DECODE(dept_no. D0020_kount. ‘X’). NULL))
Rather than coding many identical queries. NULL)) 0030. D0030_sal FROM emp WHERE emp_name LIKE ‘SMITH%’ . SUM (DECODE(dept_no. SELECT COUNT(*). NULL)) 0020. SUM (DECODE(dept_no. salary. Using DECODE
Using DECODE to reduce processing
The DECODE statement provides a way to avoid having to scan the same rows repetitively or to join the same table repetitively. SELECT ……………………… FROM emp WHERE emp_name LIKE ‘SMITH%’
. ‘X’. a DECODE function can be used. SUM(salary) FROM emp WHERE dept_no = 0020 AND emp_name LIKE ‘SMITH%’ . The same result can be achieve much more efficiently with DECODE: SELECT COUNT(DECODE(dept_no.
4. SUM(salary) FROM emp WHERE dept_no = 0030 AND emp_name like ‘SMITH%’ . D0030_kount. D0020_sal.SELECT ‘X’ FROM DUAL WHERE ‘X’ = NULL. SELECT ‘X’ FROM DUAL WHERE ‘X’ <> NULL.
SELECT COUNT(*). ‘X’. NULL)) 0030. The following SQL statements will return one row: SELECT ‘X’ FROM DUAL WHERE ‘X’ = NVL(NULL.
This approach can be extended further to include the GROUP BY clause: SELECT ………………………… FROM emp WHERE emp_name LIKE ‘SMITH%’ GROUP BY DECODE(:INPUT. emp_no. dept_no). trans_date.
5.7) = ‘CAPITAL’. amount transaction amount > 0. amount FROM transaction WHERE account_name LIKE ‘CAPITAL%’. for each clause that cannot use an index. the TRUNC function disables the index: Do not use:
. In the following examples. ‘E’.1. ‘D’. ‘D’. emp_no. trans_date. Beware of the WHEREs In some SELECT statement WHERE clauses do not use indexes at all.SEQN_FLD ‘E’. trans_date. trans_date. The SUBSTR function disables the index when it is used over an indexed column: Do not use: SELECT account_name. Use : SELECT account_name. amount transaction amount != 0. Do not use: SELECT FROM WHERE Use:
DECODE(:BLK. amount FROM transaction WHERE SUBSTR(account_name.
SELECT FROM WHERE
account_name. dept_no). there is an alternative approach that will allow to get better performance out of the SQL statements.
In the following example.
COST (Using Resource cost) 3. amount transaction amount < 2000. Do not use: SELECT account_name. account_name. account_name.) disables indexes. Do not use: SELECT FROM WHERE Use: SELECT FROM WHERE account_name. Implement missing entities and intersection tables c. trans_date. use of ||(concatenate funct. Optimizer Modes There are three types of optimizer modes. Introduce derived values b. 1. 2. amount FROM transaction WHERE account_name = ‘AMEX’ AND account_type = ‘A’.
. In the following example. trans_date. All other airthmetic operators have the same effect. Consider Partition. Re-structure the data a. amount transaction trans_date BETWEEN TRUNC(SYSDATE) AND
In the following example. trans_date. Replication to reduce the network load.SELECT FROM WHERE Use: SELECT FROM WHERE TRUNC(SYSDATE). trans_date. amount transaction TRUNC(trans_date) = TRUNC(SYSDATE). RULE (Using Access path) Default optimizer mode is CHOOSE. now Oracle check recourse to set cost based mode if you are not enabled resource_limit It will set rule based optimizer mode. amount transaction amount + 3000 < 5000.
account_name. Use: SELECT account_name. trans_date. Migration.
c. amount FROM transaction WHERE account_name || account_type = ‘AMEXA’. the + operator disables the index. CHOOSE (Default). trans_date.
& start Query options will support only COST based mode. Single row returned by unique or primary key To use this access path. 2. d. In CBO query chooses as good as or better than the RBO. Partition. It will search the records through the Access paths. Oracle considers only cpu resources. To store join tables in same cluster you have to create cluster for those tables first. When you set RULE based optimizer mode. Each of these paths are explained below with the corresponding rank associated with it. Among these paths. you should generate statistics for all db tables. Index-only table. Parallel query. force the optimizer to use cost-based. you can’t tune SQL queries those are using RULE based optimizer mode. especially for multiple joins & indexes. with unique or primary key To use this access path you have to create a HASH CLUSTER using HASH function. Oracle will never worry about COST (means resource or I/O cost). CBO relies on statistics. 3. Oracle maintains 15 access paths for each search. reverse index. 5. Points to be remembered: a. Cluster join To use this access path the join tables should be stored in the same cluster and WHERE clause should contain conditions that equate each column of the cluster key in one table with corresponding column in the other table. b. e.
. Single row returned by hash cluster join. 4. Start Transformation. the WHERE clause should have all columns in the unique or primary key with equality condition. ACCESS PATHS (Each number below. CBO improves productivity by eliminating the need for you to tune. Single row returned by CLUSTER join To use this access path. clusters & indexes. Single row returned by ROWID Eg : SELECT * FROM emp WHERE ROWID = '00000DC5. Oracle tries to apply the least rank of the path as possible. your join tables should be stored in the same cluster and WHERE clause should be return one only row. is the rank associated with the access path) 1.0001'.When you set COST based optimizer mode. Note: Unless you are clear with access path.0000. All hints except RULE. c. Your queries should apply the least rank of path.
the join tables should not be stored together in a cluster. the WHERE clause should use all columns of a composite index in equality conditions combined with AND operators. the WHERE clause should use the columns of one or more single.column indexes in equality conditions. 14. or the CONCAT function. Unbound range search on indexed column. Hash cluster key To use this access path.6. i) The query uses the MAX or MIN function to select the maximum or minimum value of either the column of a single-column index or the leading column of a composite index. a constant. ii) The argument to the MAX or MIN function can be any expression involving the column. 12. Sort merge join To use this access path. 9. 13. Bound range search on indexed column To use this access path. 7. 8. the concatenation operation (||). the WHERE clause should contain one of the conditions that use either the column of a single-column index or one or more columns of the leading portion of a composite Index (Using OR). the WHERE clause should use all columns of hash cluster key with equality condition. if the statement's WHERE clause uses columns from each table in equality conditions. To use this access path. the WHERE clause should use all columns of indexed cluster key with equality condition. ii) There must be a PRIMARY KEY or NOT NULL integrity constraint that
. 10. the WHERE clause should contains a condition that uses either the column of a single-column index or one or more columns that make up a leading portion of a composite index (using AND) 11. i) The query contains an ORDER BY clause that uses either the column of a single-column index or the leading portion of a composite index. Composite index To use this access path. iv) The statement has no WHERE clause or GROUP BY clause. Single-column index To use this access path. The index cannot be a cluster index. The index cannot be a cluster index. or the addition operator (+). MAX or MIN of indexed column To use this access path the following conditions must be true. iii) There are no other expressions in the select list.ORDER BY on indexed column To use this access path the following conditions must be true. Indexed cluster key To use this access path.
Hash join Here also Oracle performs a full table scan for dept and hash cluster scan of emp.Full table scan. Then it performs a full table scan of two tables. iii) The NLS_SORT parameter is set to BINARY in init parameter file or using statement ALTER SESSION SET NLS_SORT=BINARY. Keep in mind that full table scan is the last rank (15). your query will never use that index when you write a query with the following conditions How to make your JOINS more effective? When you write a query with two-row source. When you create a composite index for all the columns which are specified in WHERE clause. This will increase the performance.
3. 15.dno.dept where emp. Cluster join Oracle can perform a cluster join only for an equi-join that equates the cluster key columns of two tables in the same cluster. Oracle uses the path composite index (rank 8). Then Oracle performs a full table scan for dept and cluster scan of emp. Sort Merge Oracle first sorts each row of source to be joined if they have not been already sorted.dno=dept. regardless of its WHERE clause conditions. This access path is available for any SQL statement.guarantees that at least one of the indexed columns listed in the ORDER BY clause contains no nulls. I will take two tables like emp and dept to explain the joins 1. Here EMP is the Driving (outer) table and DEPT is Driven (inner) table. So. Oracle performs a full table scan of emp and a rowid scan of DEPT. Note: Even though you are having indexes. But sort merge joins can perform only for equi-joins. at any point of time try to avoid the full table scan.
. Nested loops When you write a query like select * from emp. Oracle performs one of the following joins.
both are same except that UNION uses SORT operation to eliminate the duplicate records. 3. Hash. as per commitment. use the following SQL script: select owner. use the following script select index_name. No_merge. Start_tranformation. Driving_hash. table_owner.Hints 1. Append. When you set operators UNION or UNION ALL. Hints for joins : Ordered. Noappend. Use_merge. The first table in the join order has the most highly ranked access path (eg. Index. Hints for parallel execution: Parallel. Noparallel_index. Use_hash. Index_asc. 2. Hints for Access path : Full. So. Noparallel. then UNION ALL is advisable. When you use OUTER JOIN(+) operator. Use_cancat. if you are not using any WHERE clause in a compound query and you are not worrying about duplicate records. Star. index_combine. Index_desc. Cluster. column_position from
. index_name. When you specify more tables in FROM clause. Explain Plan There is a table ‘T8000_TIC_UNIT_HISTORY’ that is created with the synonym ‘TIC_UNIT_HISTORY’. rank 5 table first and rank 7 table second and so on). column_name. The table with the outer join operator must come after the other table in the condition. Parallel_index. Rowid. Merge. Additional Hints: Cache. Use_nl. To get to know the indexes for this table. And_equal. table_name from all_indexes where table_name='T8000_TIC_UNIT_HISTORY' This gives the following result: OWNER OPNSUT IL INDEX_NAME T8000_TIC_UNIT_HIS TORY_X TABLE_OWN TABLE_NAME ER OPNSUTIL T8000_TIC_UNIT_HISTORY
To view the columns that are used in this index. Hash_Aj. Index_ffs. Nocache.
I shall describe in detail about how to use the PLAN_TABLE. The structure of the PLAN_TABLE is as follows: Name Null? STATEMENT_ID TIMESTAMP REMARKS OPERATION OPTIONS OBJECT_NODE OBJECT_OWNER OBJECT_NAME OBJECT_INSTANC E OBJECT_TYPE OPTIMIZER SEARCH_COLUMNS ID PARENT_ID POSITION OTHER Type VARCHAR2(30) DATE VARCHAR2(80) VARCHAR2(30) VARCHAR2(30) VARCHAR2(128) VARCHAR2(30) VARCHAR2(30) NUMBER VARCHAR2(30) VARCHAR2(255) NUMBER NUMBER NUMBER NUMBER LONG
From this. which will be used for the purpose of this document. will be the following fields: STATEMENT_ID. and POSITION We use the following SQL script. OBJECT_NAME. the main fields. ID. it is basically analyzing the queries.all_ind_columns where index_name='T8000_TIC_UNIT_HISTORY_X' This gives the following result INDEX_NAME COLUMN_NAM E COLUMN_POSIT ION 1
T8000_TIC_UNIT_HIST CURR_VIN ORY_X
We can use table ‘PLAN_TABLE’ to explain the SQL queries. By saying ‘explaining SQL queries’. OPERATION. OPTIONS. which index was used for each table in the SQL. which access path was used for the query. so as to return rows that will say. which is used to explain the query. etc. OBJECT_TYPE. explain plan set statement_id = 'pcs' for select * from tic_unit_history where
. based on the example above. what is I/O cost of processing the queries.
I’ve highlighted the field names of the PLAN_TABLE in bold. Now Row 1: This row says that the SQL script. The unit of measure is unimportant. is that the lessor the cost. though. Row 3: This row specifies the index that was used to scan the table. Row 2: This row specifies which table was accessed and which access path was used. we will be using this field to identify the required rows. 0.curr_vin='1FTFF25G9DKA45510' Let us see what this means: The statement_id field is the field that is set by us. Note that the statement_id value given in this script is the same as that given in the previous script (and it is casesensitive).2*(LEVEL-1))||operation||' '||options||' '|| object_name ||' '||DECODE(id. While analyzing the rows returned. is specified after the ‘for’ keyword. to identify a unique operation. So. use the following script: SELECT LPAD(' '. The query. the following rows: Query Plan SELECT STATEMENT Cost = 2 TABLE ACCESS BY ROWID T8000_TIC_UNIT_HISTORY INDEX UNIQUE SCAN T8000_TIC_UNIT_HISTORY_X There’s only one column that is returned and 3 rows. what this means. This means that the I/O cost or resource access was 2. in a sort of pseudo-code language is: “Explain the plan for this query and set the statement_id=’pcs’ for all the rows that are returned” To analyze the rows that are returned. We can use any literal to set the field. was a ‘SELECT’ operation. What is important. which was to be explained. This script will return.
. the fast the query is going to execute. that is to be explained. (Remember that SQL script which we had used for explaining is : “select * from tic_unit_history where curr_vin='1FTFF25G9DKA45510'”) It also says that ‘Cost = 2’. The “Query Plan” is the header. 'Cost = '||position) "Query Plan" FROM plan_table START WITH id = 0 AND statement_id = 'pcs' CONNECT BY PRIOR id = parent_id AND statement_id ='pcs'.
and that index consists of only one column. in the SQL script that was to be explained. The indexes and the columns in the indexes for this table is as follows : Index Name I4310_PK_TAX_LOCAT IONS I4310_IX2_TAX_LOCA TIONS I4310_IX2_TAX_LOCA TIONS I4310_IX2_TAX_LOCA TIONS I4310_IX2_TAX_LOCA TIONS I4310_IX2_TAX_LOCA TIONS I4310_IX3_TAX_LOCA TIONS Column Name TAX_LOC_ID COUNTRY_CODE STATE_OR_PROV_ABBR COUNTY_NAME CITY_NAME ZIP_OR_POSTAL_CODE OWNER_TAX_LOC_ID Column Position 1 1 2 3 4 5 1
The script for explaining is as follows: select * from tax_locations where tax_loc_id between 900000 and 900100 So the explain script will be: explain plan set statement_id = 'pcs' for select * from tax_locations where tax_loc_id between 900000 and 900100 Analysis script is the same as before. it takes 0. This will return the following: Query Plan SELECT STATEMENT Cost = 29 TABLE ACCESS BY ROWID T4310_TAX_LOCATIONS INDEX RANGE SCAN I4310_PK_TAX_LOCATIONS When we execute the query.302 seconds to return 101 records. it took 0. there is only one index for the table ‘tic_unit_history’. Why I used this specific column is because. Let us explain another SQL query. I have used the column ‘curr_vin’ in the WHERE clause. which was present in the index. When I executed the explained SQL script.
. That is why the optimizer used the index. in order that the query be processed faster.604 seconds to return 1 record. We have a table T4310_TAX_LOCATIONS with the synonym TAX_LOCATIONS. which is ‘curr_vin’. So.Note that. I specifically used the column in the WHERE clause.
in the WHERE clause. Instead of using BETWEEN. Let’s try an example by using the index ‘I4310_IX2_TAX_LOCATIONS’. we use the relational operators <= and >=. we’ll try to explain the query.Suppose we modify the query a bit. We must note that.143 seconds to return 5 records Let’s modify the query so as to include the country_code also. in the normal case.152 seconds to return the same 101 records. Note that the time reduction is 50%. But the query executes in 0. Anyway. So we might consider this insignificant. Consider the following query: select * from tax_locations where state_or_prov_abbr='IL' and county_name='ADAMS' and city_name='QUINCY' The explain script will be: explain plan set statement_id = 'pcs' for select * from tax_locations where state_or_prov_abbr='IL' and county_name='ADAMS' and city_name='QUINCY' This analysis script will return: Query Plan SELECT STATEMENT Cost = 573 TABLE ACCESS FULL T4310_TAX_LOCATIONS Note that the cost is 573 units and the access path that was used was Full Table Scan. The execution time for this query was 2. The query will be as follows: select * from tax_locations where tax_loc_id >= 900000 and tax_loc_id <=900100 The explain script will be: explain plan set statement_id = 'pcs' for select * from tax_locations where tax_loc_id >= 900000 and tax_loc_id <=900100 The analysis will be the same as before. select * from tax_locations where country_code='US' and state_or_prov_abbr='IL' and county_name='ADAMS' and city_name='QUINCY' The explain script is as follows: explain plan set statement_id = 'pcs' for select * from tax_locations where country_code='US' and state_or_prov_abbr='IL' and county_name='ADAMS' and city_name='QUINCY'
. all records in this table have country_code=’US’.
you may find that the optimizer still does not use the index that you want. 2) While explaining the queries. the optimizer found all the columns in the index. And for your information. provided the same results are returned in less time. with all the tuning that you have done. In such cases.194 seconds to return the same 5 records as the previous query.And the analysis script returns: Query Plan SELECT STATEMENT Cost = 3 TABLE ACCESS BY ROWID T4310_TAX_LOCATIONS INDEX RANGE SCAN I4310_IX2_TAX_LOCATIONS Now. If it means adding insignificant fields in the WHERE clause. which you want to use. In most cases. So it used the index ‘I4310_IX2_TAX_LOCATIONS’ to process the query. as a hint. 3) The main point is that while we write queries. Depending on our requirement. go ahead and use it. we will have to find out. Oracle does not execute the query. we have reduced the cost from 573 units to 3 units.
. except the last one (ZIP_OR_POSTAL_CODE) in the WHERE clause of the query. That’s a time saving of about 90%. the query took 0. a table will have more than one index. care should be taken to use specific indexes. which index to use. Some general points to note: 1) This is just a tool with which we can analyze our queries. This is because. with the ‘insignificant’ country_code column. 5) In some cases. 4) All optimizer modes do not return the value for COST. it is better to specify the index.