which results in the following execution plan and statistics from Autotrace:Elapsed: 00:00:00.41Execution Plan--- 0 SELECT STATEMENT Optimizer=RULE 1 0 NESTED LOOPS 2 1 TABLE ACCESS BY I
Trang 1which results in the following execution plan and statistics from Autotrace:
Elapsed: 00:00:00.41Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (BY INDEX ROWID) OF ‘EMPLOYEE’
3 2 INDEX (RANGE SCAN) OF ‘ID_EMP’ (NON-UNIQUE)
4 1 INDEX (RANGE SCAN) OF ‘ID_DEPT’ (NON-UNIQUE)Statistics
To force the optimizer to do a full table scan, append a +0 to the left side of theEMPNO < 7800line in the WHERE clause:
SELECT empno, dnameFROM dept b, EMPLOYEE aWHERE dname=’RESEARCH’
and empno+0< 7950and a.deptno=b.deptno;
In the following output, you’ll see there’s not much improvement In fact, we’ve
managed to increase the number of logical I/Os by 12 Also, the runtime has about
doubled
Elapsed: 00:00:00.51Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
Trang 21 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF ‘EMPLOYEE’
3 1 INDEX (RANGE SCAN) OF ‘ID_DEPT’ (NON-UNIQUE)Statistics
SELECT empno, dnameFROM dept b, EMPLOYEE aWHERE dname=’RESEARCH’
and empno< 7950 and a.deptno||’ ’=b.deptno||’ ’;
Now look at the runtime; it’s slightly better—and the logical I/Os are very muchimproved!
Elapsed: 00:00:00.40Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF ‘DEPT’
3 1 TABLE ACCESS (BY INDEX ROWID) OF ‘EMPLOYEE’
4 3 INDEX (RANGE SCAN) OF ‘ID_EMP’ (NON-UNIQUE)Statistics
Trang 3So the big gain here appears to have come from disabling the DEPT index, whichcaused the RBO to make the DEPT table the driving table Instead of 24 logical I/Os,
we got 15—a 62 percent improvement in performance Not bad As you can see, abling indexes can be a good thing or it can be a bad thing
dis-If you are using CBO, you can also disable the use of an index by using theNO_INDEX hint You can use the hint without any parameters, or you can includeparameters that cause certain indexes to be ignored by the optimizer For example, ifyou didn’t want to use the IX_EMPLOYEE index, you’d use
NO_INDEX(ix_employee)
Tuning Rule-Based Statements
One of the unfortunate facts of life about RBO is that the tuning options are what limited In this section we will discuss some issues that can make an impact onthe overall performance of your RBO-based SQL statements
some-Choosing the Driving Table Wisely
As discussed, the driving table is the table that provides the row sources to be resolved
in the second table in the join Often the driving table will be accessed through a fulltable scan, if the column is not indexed In a rule-based statement, the driving table isgenerally the table with the lowest access path, but not always When the access pathsare alike between two tables, you can change the join order in RBO by reversing thetable order in the FROM clause This is because the last table in the FROM clause will
be the driving table, if the access paths for both tables are the same Because the ving table is the main row source, you always want it to be the table that will generatethe smallest and thus most selective row source
Let’s examine an example in which you can see the impact of a well-chosen ving table Assume you have an EMP table and a DEPT table, both of which are notindexed Here is the first query:
dri-SELECT a.empno, b.dnameFROM emp a, dept bWHERE a.deptno=b.deptno;
And here are the execution plan and performance stats:
Elapsed: 00:00:39.87Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
1 0 MERGE JOIN
Trang 43 2 TABLE ACCESS (FULL) OF ‘DEPT’
4 1 SORT (JOIN)
5 4 TABLE ACCESS (FULL) OF ‘EMP’
Statistics -
1391187 bytes sent via SQL*Net to client
212546 bytes received via SQL*Net from client
1913 SQL*Net roundtrips to/from client
as follows:
SELECT a.empno, b.dnameFROM dept b, emp aWHERE a.deptno=b.deptno;
Take a look at the execution plan and performance stats now, and notice the reversal
of the join order of the DEPT and EMP tables:
Elapsed: 00:00:30.14Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
P A R TIII
Trang 53068 physical reads
25736 redo size
1391187 bytes sent via SQL*Net to client
212546 bytes received via SQL*Net from client
1913 SQL*Net roundtrips to/from client
Accounting for Indexes
Of course, indexes can make for even more interesting tuning Assume you have anindex on the DEPT table that you are querying You create the index on the joincolumns for DEPT, DEPTNO, and DNAME What do you suppose will happen? Let’srun the original query first Then we’ll reverse the order of the tables in the query andchange the driving table
Elapsed: 00:00:23.84Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF ‘EMP’
3 1 INDEX (RANGE SCAN) OF ‘IX_DEPT’ (NON-UNIQUE)Statistics
908283 bytes sent via SQL*Net to client
212546 bytes received via SQL*Net from client
1913 SQL*Net roundtrips to/from client
8 sorts (memory)
0 sorts (disk)
Trang 6As you might expect, Oracle has picked up the index and used it This has improvedthe overall performance of the query over the original by some 45 percent (which is alesson unto itself) Now, let’s see what happens when we reverse the FROM clause:
Elapsed: 00:00:24.65Execution Plan -
0 SELECT STATEMENT Optimizer=RULE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF ‘EMP’
3 1 INDEX (RANGE SCAN) OF ‘IX_DEPT’ (NON-UNIQUE)Statistics
908283 bytes sent via SQL*Net to client
212546 bytes received via SQL*Net from client
1913 SQL*Net roundtrips to/from client
Tuning Cost-Based Statements
CBO tuning is a whole different animal than RBO tuning In cost-based optimization,you have many more options available to you in terms of access paths CBO issmarter than RBO because CBO takes advantage of generated statistics And CBOqueries are easier to tune because you can utilize hints to tell the optimizer whichaccess paths are optimal
Using Hints
Hints are part of CBO magic and probably your most important SQL tuning tool—
Beyond Simple Database Management
P A R TIII
Trang 7what access paths to take when generating the execution plan for your SQL ment The CBO will not always follow your hints, for one reason or another, and youmight find that it takes a combination of hints to get the response you want fromSQL statement.
To use a hint in a SQL statement, you place it immediately after the SELECT ment in a comment (/* */) bracket, with a + immediately after the first /* symbol.For example:
state-/*+ RULE */
The format of the hint designation is important You must put the + immediatelyafter the /* If you leave a space between the /* and the +, you invalidate the hint.You can also use the alternate + syntax for hint inclusion (as in + RULE)
A SQL statement can comprise multiple hints; each hint is separated by a space.Hints often have associated parameters, one of which is often the name of the table towhich you want the hint applied For example, when using the FULL hint to get fulltable scans, you give the hint a parameter specifying the name of the table you want
to have the full table scan, as in
When you use multiple hints, Oracle may ignore some of them depending on theaccess paths it decides to use If a certain hint is very important but is not beingimplemented, you can try to force it by controlling the order of the join (using theORDERED hint) Thus, if you force the table with the preferred hint to be the drivingtable of the join by using the ORDERED hint, Oracle is more likely to use the accesspath directed in the hint
Tables 16.9 through 16.14 list and classify all hints available in Oracle8i and how
to use them
Trang 8TABLE 16.9: OPTIMIZATION APPROACH HINTS
ALL_ROWS None Causes Oracle to optimize the SQL statement for
throughput rather than response This modetends to prefer full table scans and merge joinsover index lookups
Example: /*+ ALL_ROWS */
FIRST_ROWS None Causes Oracle to optimize the SQL statement for
response rather than throughput This modetends to prefer index lookups and nested looplookups
Example: /*+ FIRST_ROWS */
CHOOSE None Causes the statement to run in RULE mode if no
statistics are available If statistics are available,then the statement will run in cost-based mode
Example: /*+ CHOOSE */
RULE None Causes the statement to run in rule-based mode
regardless of the current system setting OPTIMIZER_MODE
Example: /*+ RULE */
TABLE 16.10: ACCESS METHOD HINTS
FULL Table name Forces a full table scan of the listed table If table
has an alias, then the alias rather than the tablename must be used in the hint
Example: /*+ FULL(e) */
ROWID Table name Suggests that the optimizer do a table scan by
ROWID for the listed table
Example: /*+ ROWID(e) */
CLUSTER Table name Suggests that the optimizer do a cluster scan to
access a specific table
Example: /*+ CLUSTER(e) */
Beyond Simple Database Management
P A R TIII
Trang 9TABLE 16.10: ACCESS METHOD HINTS (CONTINUED)
HASH Table name Suggests that the optimizer do a hash scan to
access the table specified Applies only to tablesstored in a cluster
Example: /*+ HASH(e) */
INDEX Table name and Specifies the index to be used to access
index names the given table Oracle will not consider a full
table scan or a scan on another index on thetable Applies to both B*Tree and bitmap indexes.See also INDEX_COMBINE, which Oracle suggestswhen using bitmap indexes
When this hint specifies multiple indexes, Oracleselects the one that offers the best access
If no index name is specified, the optimizerchooses from all indexes available on the table.Full table scans are not considered
In multiple index listings or where no index islisted, Oracle may decide to scan multiple indexesand merge the results
Example: /*+ INDEX (e ix_emp_01 ix_emp_02) */INDEX_ASC Table name and Designates an index scan for the table specified
index names Essentially the same as the INDEX hint
Example: /*+ INDEX_ASC(e ix_bit_emp_01) */INDEX_COMBINE Table name bitmap Designates the specified bitmap index as
index names the access path to the table specified If no
indexes are listed, the optimizer uses whatevercombinations of bitmap indexes have the best-calculated cost If multiple indexes are listed,Oracle will use the best combination of indexesthat it finds
Example: /*+ INDEX_COMBINE(e ix_bit_emp_01)*/
INDEX_JOIN Table name and Designates an index join containing the
index names specified indexes as the access path to the table
specified
Example: /*+ INDEX_JOIN */
Trang 10TABLE 16.10: ACCESS METHOD HINTS (CONTINUED)
INDEX_DESC Table name and Causes the optimizer to choose a plan
index names that instigates an index scan for the given table If
during the execution the query an index rangescan is used, the index will be scanned in
descendingorder (the reverse of the defaultOracle setting for index scans)
Example: /*+ INDEX_DESC */
INDEX_FFS Table name and Designates a fast full scan on the index
index name specified, instead of a full scan of the associated
table
Example: /*+ INDEX_FFS(emp ix_emp_01) */
NO_INDEX Table name and Causes the specified indexes associated
index names with the listed table to be ignored by the
opti-mizer If no indexes are listed in this hint, then noindexes will be considered for the table
Example: /*+ NO_INDEX(emp ix_emp_01) */
AND_EQUAL Table name and Causes the optimizer to choose an
index names execution plan for access to the listed table that
includes a merge scan of the indexes listed Atleast two indexes must be specified in the hint,and no more than five
Example: /*+ AND_EQUAL (emp ix_emp_02ix_emp_03 ix_emp_04) */
USE_CONCAT None Forces a SQL statement using OR conditions in
the WHERE clause to be transformed into a pound query (i.e., using a UNION ALL keyword)
com-Example: /*+ USE_CONCAT */
NO_EXPAND None This hint removes OR expansions from
considera-tion when the query is being optimized It is theopposite of the USE_CONCAT query
Example: /*+ NO_EXPAND */
REWRITE View name Causes Oracle to search for eligible materialized
views that could be used to rewrite the SQL queryassociated with the hint You may specify one ormore materialized view names to be considered
Example: /*+ REWRITE */ Beyond Simple Database Management
P A R TIII
Trang 11TABLE 16.10: ACCESS METHOD HINTS (CONTINUED)
NOREWRITE None Disables query REWRITE for the given SQL
state-ment, regardless of the QUERY_REWRITE_ENABLED setting
Example: /*+ NOREWRITE */
TABLE 16.11: JOIN ORDER HINTS
ORDERED None Causes Oracle to join tables in the order shown in
the statement’s FROM clause The join order isfrom left to right
Example:: /* ORDERED */
STAR None Suggests that the optimizer use a star query plan
if possible, which causes the largest table(assumed to be the fact table) in the query to bejoined last in the join order This table must have
a concatenated index with at least three columnsthat are part of the query in question Appliesonly when there are three or more tables in thejoin Do not include conflicting accesses or joinhints with the STAR hint See Chapter 19
Example: /*+ STAR */
TABLE 16.12: JOIN OPERATION HINTS
USE_NL Table names Designates a nested loop join when joining the
specified table to another row source Specifiedtable will be the inner table of the join
Example: /*+ USE_NL */
Trang 12TABLE 16.12: JOIN OPERATION HINTS (CONTINUED)
USE_MERGE Table names Designates a sort merge join when joining the
specified table with another row source
Example: /*+ USE_MERGE */
USE_HASH Table names Causes Oracle to join the specified table with
another row source by using a hash join
Example: /*+ USE_HASH */
DRIVING_SITE Table name (remote) Causes the row source from the local table being
joined to the specified remote table to be sent tothe remote system and processed on that system
Query result is then returned to the local site
Example: /* DRIVING_SITE(emp) */
LEADING Table name Causes the specified table to be used as the first
table (or the driving table) of the join Specifyingmultiple tables causes this hint to be ignored TheORDERED hint overrides this hint
Example: /*+ HASH_AJ (emp) */
HASH_SJ None Used when doing EXISTS subqueries Can cause
an EXISTS subquery to be transformed into a hashsemi-join or a sort merge semi-join to occur Hasthe same effect as setting the parameteralways_semi_join=HASH or MERGE
Example: /*+ HASH_SJ */
Beyond Simple Database Management
P A R TIII
Trang 13TABLE 16.13: PARALLEL EXECUTION HINTS
PARALLEL Table name; degree Specifies desired number of concurrent parallel
of parallelism; server processes to be used for the parallel table number of instances scan operations Applies to SELECT, INSERT,
UPDATE, and DELETE statements Hint is ignored
if parallel processing is disallowed Oracle willdecide these parameters based on init.ora set-tings if degree of parallelism isn’t specified; ifnumber of instances isn’t specified; or if the key-word DEFAULT is used
Examples:
/*+ PARALLEL(emp 3,2) */
/*+ PARALLEL(emp 4,1) PARALLEL(dept 4,1) *//*+ FULL(emp) PARALLEL(emp 5) */
/*+ PARALLEL(emp DEFAULT,DEFAULT) */NOPARALLEL Table name Causes Oracle to override the specified table’s
PARALLEL setting, ensuring that access to thetable will not be via parallel server processing.Example: /*+ NOPARALLEL(dept) */
APPEND None Used only with an INSERT clause, causing it to be
a direct insert operation No free space in rently allocated blocks is used If an INSERT is par-allelized, then APPEND mode will be used bydefault
cur-Example: /*+ APPEND */
NOAPPEND None Causes APPEND operations to be overridden
Example: /*+ NOAPPEND */
PARALLEL_INDEX Index name; degree Specifies desired number of concurrent parallel
of parallelism; server processes to be used for the parallel index number of instances operations Applies only to partitioned indexes
Hint is ignored if parallel processing is disallowed.Oracle will decide these parameters based oninit.ora settings if degree of parallelism isn’tspecified; if number of instances isn’t specified; or
if the keyword DEFAULT is used
Examples:
/*+ PARALLEL_INDEX(ix_emp 3,2) */
/*+ PARALLEL(ix_emp DEFAULT,DEFAULT) */
Trang 14TABLE 16.13: PARALLEL EXECUTION HINTS
NOPARALLEL_ Table name and Disables parallel index scans on specified indexes
INDEX index names Example: /*+ NOPARALLEL_INDEX(emp
ix_emp_01) */
TABLE 16.14: MISCELLANEOUS HINTS
CACHE Table name Directs Oracle to place the blocks retrieved from
the specified table during a full table scan at theMRU end of the database buffer cache ratherthan the LRU end
Example: /*+ CACHE(emp) */
NOCACHE Table name Overrides specified table’s CACHE setting, and
causes full scans to load rows into the LRU end ofthe database buffer cache (the default behavior)
Example: /*+ NOCACHE(emp) */
MERGE Table name Applies to views that are part of a SQL statement
(such as inline views) Enables complex mergingbehaviors such as merging the inline view intothe SQL statement and using the inline viewwhen the inline view contains GROUP BY or DIS-TINCT operators
Example: /*+ MERGE (d) */
Note: Complex view merging is not the defaultCBO behavior It must be enabled by setting theparameter optimizer_features_enable, or by usingthe MERGE hint, or by setting the parameter_complex_view_merging
NO_MERGE Table name Causes Oracle not to merge mergeable views on
the specified table
Example: /*+ NO_MERGE */
Beyond Simple Database Management
P A R TIII
Trang 15TABLE 16.14: MISCELLANEOUS HINTS (CONTINUED)
UNNEST None Causes the optimizer to check validity of subquery
block in a SQL statement, allowing unnesting to
be enabled without Oracle checking the query’s heuristics
sub-Example: /*+ UNNEST */
Example: /*+ NO_UNNEST */
PUSH_SUBQ None Causes nonmerged subqueries to be evaluated as
early as possible in statement’s execution Example: /*+ PUSH_SUBQ */
STAR_ None Forces the optimizer to use the best star TRANSFORMATION tion access plan Does not guarantee that the trans-
transforma-formation will take place
Monitoring and Managing Excessive Hard Parsing
You can use several methods to analyze your SQL statements and determine if sive parsing is happening in your Oracle system:
exces-• You can trace the statement’s execution in your session using Oracle’s tracefacility This method is explained in a later section
• Another option is to use the V$SQLAREA dynamic performance view If thevalue in the PARSE_CALLS column is close to that in the EXECUTIONS columnfor the same statement (and the number of executions is significant), it’s a sig-nal that you should investigate why the statement is being reparsed
Trang 16• You can use V$SESSTAT view to get two other valuable statistics: PARSECOUNT(HARD) and EXECUTIONS For example, this query will produce the values youneed:
SELECT a.sid, a.statistic#, b.name, a.valueFROM v$sesstat a, v$statname b
WHERE a.statistic# IN (SELECT statistic# FROM v$statname
WHERE name IN(‘parse count (hard)’,’execute count’) )AND a.statistic#=b.statistic#
actu-that will work is to analyze the application and look for a way to reduce overall parse
calls coming from it In other words, this is a problem with the private memory cated by the application, rather than shared database memory
allo-Further discussion of how to actually change applications in order to reduce parsecalls is beyond the scope of this book
NOTE If you are running MTS, the private SQL area is stored in the SGA For more aboutMTS and configuration differences when running in that mode, see Chapter 9
In terms of shared SQL areas, you can determine if you have reparsing issues byusing this query from Chapter 15:
SELECT ((SUM(reloads) / SUM(pins) ) * 100) “Library Cache Reload Ratio”
If you find that the library cache reload ratio is bad, it may well mean that the size
of the shared pool is insufficient for the database In this event, Oracle will deallocate
Beyond Simple Database Management
P A R TIII
Trang 17using reusable SQL, you’ll find SQL statements with a small number of executions, andthe number of parse calls will be almost the same as the number of execution calls.
Be careful when you’re setting the size of the shared pool, however It’s quite ble to make it too large Does that surprise you? Remember that for each SQL state-ment parsed, Oracle must verify that the statement is already in the shared pool Ifyou have a large shared pool, and it has also become particularly fragmented, youmay find that parse times (hard and soft) will grow longer and longer Eventually ittakes longer to find like SQL statements than it would to just parse the statement inthe first place
possi-The CURSOR_SHARING Parameter in Oracle8i
In Oracle 8.1.5 and later, an additional solution to parsing problems is theCURSOR_SHARING parameter Setting CURSOR_SHARING=FORCE in the databasesparameter file has the effect of replacing literal values in SQL statements with system-generated bind variables The parameter has two values: EXACT (the default) andFORCE Setting CURSOR_SHARING = FORCE can reduce the time required for reparseoperations (but does not eliminate parse operations) It also reduces the amount ofmemory required for the SGA and may improve SQL query performance
The CURSOR_SHARING parameter can be a great boon Look at the results of using
it on an Oracle system with the SCOTT/TIGER EMP table Here is the first query cuted against the table:
exe-SELECT * FROM EMP WHERE empno=7369;
Now, here is an excerpt of what the V$SQLAREA looked like after this query:
SELECT substr(sql_text,1,40) sql_text, executions, loads, parse_callsFROM v$sqlarea;
and here is the output:
SQL_TEXT EXECUTIONS LOADS PARSE_CALLS - - -SELECT * FROM EMP WHERE empno=:SYS_B_0 1 1 1
Notice the bind variable :SYS_B_0 Oracle replaced the literal value 7369 with the system-generated bind variable :SYS_B_0
Let’s run a similar query:
SELECT * FROM EMP WHERE empno=7900;
Oracle replaces the system bind variable :SYS_B_0 with the value 7900, and when youquery V$SQLAREA you get this result:
SQL_TEXT EXECUTIONS LOADS PARSE_CALLS - - -
Trang 18The EXECUTIONS parameter has increased, as has the PARSE_CALLS parameter (this
is the same action you would see if you explicitly used a bind variable) The LOADSparameter has not increased, however, because this statement had to be loaded onlyonce rather than twice There is only one row in V$SQLAREA for this query, whichindicates that Oracle replaced the literal with the bind value and used the existingSQL query in the shared SQL area
You can see that if the shared SQL area contains lots of SQL statements that aresimilar except for certain literals in the WHERE clause, you might benefit from theuse of CURSOR_SHARING set to FORCE The default for this setting is CURSOR_
SHARING=EXACT, which will require that SQL statements be exactly alike to be reused
N OTE Oracle does not recommend setting CURSOR_SHARING to FORCE in a DSS environment
TI P You shouldn’t set CURSOR_SHARING to FORCE if you are using complex queries,query rewrite, or stored outlines However, experience tells us never to rule out anythinguntil it’s proven unworkable Try it: Set CURSOR_SHARING = FORCE and run some tests Ifyou see improvements, great If not, reset CURSOR_SHARING and don’t use it
The CURSOR_SPACE_FOR_TIME Parameter
The init.ora parameter CURSOR_SPACE_FOR_TIME can also be of some help withparsing problems This parameter has two values: TRUE and FALSE (the default)
When set to TRUE, it allows the deallocation of a shared SQL area only when all sors associated with the statement have been closed Oracle’s default behavior is thatshared SQL areas may be released, even if there are current cursors (inactive) using thatshared SQL area This approach saves time because Oracle doesn’t need to verify thatthe shared SQL area is in the cache Also, setting this parameter to TRUE prevents thedeallocation of private SQL areas until the associated cursors are closed
cur-By default, Oracle can (and will) remove the shared SQL area if it is aged out foranother statement Doing so can cause a small performance impact, but it is generallyinsignificant If you set CURSOR_SPACE_FOR_TIME to TRUE, it is possible that Oraclewill be unable to allocate memory in the shared SQL area, and it will unfortunatelyreturn an error to the user So leave CURSOR_SPACE_FOR_TIME set to the default
Beyond Simple Database Management
P A R TIII
Trang 19Other Tuning Suggestions
Some of the following miscellaneous tuning suggestions apply only to RBO, and someapply to both RBO and CBO
Using Function-Based Indexes
The notion of function-based indexes is new as of Oracle8i These indexes allow you
to use a function in the predicate of a WHERE clause (Prior to Oracle8i, use of a tion in a WHERE clause’s predicate forced an I/O-expensive full table scan.)
func-A function-based index is based on the function you use in the SQL statement Forexample, the following SQL statement contains the UPPER function in the WHEREclause, to accommodate mixed-case names:
SELECT empno, ename, salFROM employee
WHERE upper(ename) = ‘KING’;
In this case, the execution plan tells the story, a full table scan of the EMPLOYEEtable:
Execution Plan -
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF ‘EMPLOYEE’
If we create a function-based index, however, we end up with an index scan Here
is the statement to create the function-based index:
CREATE INDEX id_func_employee_ename_01 on employee (upper(ename));
We now query the EMPLOYEE table again, and voilà! Here is the new execution plan:
Execution Plan -
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=11)
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘EMPLOYEE’ (Cost=1 Card=1 Bytes=11)
2 1 INDEX (RANGE SCAN) OF ‘ID_FUNC_EMPLOYEE_ENAME_01’ (NON-UNIQUE)
(Cost=1 Card=1)
There are several database configuration (init.ora) requirements associated withfunction-based indexes:
• The parameter QUERY_REWRITE_INTEGRITY must be set to TRUSTED
• The parameter QUERY_REWRITE_ENABLED must be set to TRUE
• The parameter COMPATIBLE must be 8.1.0.0.0 or greater
Trang 20Also, remember these rules:
• In order to use the function-based index after it is created, the table must beanalyzed
• Since NULL values are not stored in indexes, the query must not return anyNULL values from the function
TI P Make sure you check your execution plans if you expect to use a function-basedindex You’lI often have to include a hint to get the SQL statement to use a function-basedindex, because the optimizer does not choose it as the access path of choice
Accidentally Forcing Table Scans
Unfortunately, it’s possible to code a SQL statement that inhibits index accesses, sowatch out Here are a few statements that will do it:
Using the != operator (RBO only) Oracle will not use an index if you usethe != operator If you want to make sure an index is used, replace the != opera-tor with an IN clause that contains the acceptable values For example, replacethis statement:
SELECT empno FROM EMPLOYEEWHERE deptno != 30;
with this statement:
SELECT empno FROM EMPLOYEEWHERE deptno in (10,20,40,50);
NOTE When using CBO, != operators can take advantage of indexes by using full indexscans You may need to use hints to force this action
Searching for NULL values in columns (RBO, CBO) Because NULLvalues are not stored in indexes, query searching for NULL values in a columnwill force a full table scan If you are going to create an index on a column, con-sider making that column NOT NULL so as to avoid this problem
Searching for values using the NOT NULL clause (RBO only) This Beyond Simple Database Management
P A R TIII