 |
|
Oracle SQL Tuning with function-based indexesOracle Tips by Burleson Consulting |
Oracle function-based indexes are a
super silver bullet for optimizing your SQL to do a minimum amount
of I/O to get the rows that you need.
Here are details on using
function based indexes.
Issues with function-based
indexes
One of the most common Oracle SQL tuning problems are full-table scans
that are imposed by invalidating a WHERE clause predicate with an
Oracle built-in Function (BIF). This problem is especially
prevalent when constraining SQL queries for date ranges because of the
intrinsic encryption of the relational database DATE datatype.
For example, these WHERE clause predicates might invoke an unexpected
full-table scan:
WHERE trunc(ship_date) > trunc(sysdate-7);
WHERE to_char(ship_date,'YYYY-MM-DD') = '2004-01-04';
Even though the ship_date column may
have an index, the trunc and to_char built-in functions will
invalidate the index, causing sub-optimal execution with unnecessary
I/O:
-
A less selective index would be
used.
-
A full-table scan might be
performed.
To avoid the index invalidation
issues you have several options:
1. Fix Predicate - You can rewrite the query to leave the
ship_date predicate alone:
WHERE ship_date >= trunc(ship_date-7) + 1;
WHERE ship_date = to_date(?2004-01-04?,'YYYY-MM-DD');
2. Call FBI - Create a function-based index on the predicate:
Create index trunc_ship_date on product(trunc(ship_date));
Create index char_ship_date on product(to_char(ship_date,'YYYY-MM-DD');
3. Add Column - You could add a redundant column to the table.
This is an old Oracle7 trick that was used before the invention of
function-based indexes.
alter table product add trunc_ship_date varchar 40;
update product set trunc_ship_date = trunc(ship_date);
In sum, function-based indexes
(FBIs) are a Godsend for the Oracle DBA who has to remove unnecessary
full-table scans or fix sub-optimal index choices. Using an FBI can
positively effect all SQL statements that have the matching predicate
and speed-up an entire database.
Once an FBI is created, you need to create CBO
statistics, but beware that there are numerous bugs and issues when
analyzing a function-based index. See these important notes on
statistics and
function-based indexes.
After creating a function-based index, you want
to re-gather table statistics and get extended statistics on the
function.
Create an FBI on emp_nbr column with NULL values:
create index
emp_null_emp_nbr_idx
on
emp
(nvl(ename,o));
To make the function-based index work, we must now analyze the index.
Depending you your release, these methods are appropriate:
EXEC DBMS_STATS.gather_index_stats('EMP', ?emp_null_emp_nbr_idx?);
In this case, we analyze the function-based index
using the method_opt argument set to FOR ALL HIDDEN
COLUMNS:
exec
dbms_stats.gather_table_stats(
ownname=>null,
tabname=> 'EMP',
estimate_percent=>null,
cascade=>true,
method_opt=> ?FOR ALL HIDDEN COLUMNS
SIZE 1′ );
In Oracle 11g and beyond, Oracle recommends analyzing ?extended?
statistics on function-based indexes:
begin
dbms_stats.gather_table_stats (
ownname => 'SCOTT',
tabname => 'EMP',
method_opt => 'for all columns size
skewonly for columns (nvl(ename,o))'
);
end;
Also, see these related notes on
FBI:
|
|
Get the Complete
Oracle SQL Tuning Information
The landmark book
"Advanced Oracle
SQL Tuning The Definitive Reference" is
filled with valuable information on Oracle SQL Tuning.
This book includes scripts and tools to hypercharge Oracle 11g
performance and you can
buy it
for 30% off directly from the publisher.
|
|