Indexing Strategies for Oracle Databases - Beyond the Create Index Statement
-
Upload
sean-scott -
Category
Data & Analytics
-
view
107 -
download
2
description
Transcript of Indexing Strategies for Oracle Databases - Beyond the Create Index Statement
INDEXING STRATEGIESSean Scott
Oracle DBA, Bodybuilding.com
“An index is an optional structure, associated with a table or table cluster, that can sometimes speed data access.”
B-TREE INDEXES
• Most common type of index
• Data is ordered within the index
• Consists of branches and leaves
B-TREE INDEXES
B-TREE INDEXES
• Options include
• Unique
• Descending
• Reverse Key
• Index Organized Tables
• Composite, Covering, Concatenated
• Compressed
REVERSE KEY INDEXES
• Creates a “mirror image” of the key
• UTOUG would become GUOTU
• Used to spread block splits and avoid hot blocks in RAC environments
• No index range scans
• Lots of conflicting information
• Test extensively, and use with caution
REVERSE KEY INDEXES
• Two implementations:
• last_updated_date in a customer order table
• Sequentially updated primary key
REVERSE KEY INDEXES
• Things to watch for:
• Increase in db sequential read wait events
• Backup time increase
• Space use increase
INDEX ORGANIZED TABLES
• Stores data and index in the same segment
• Must have a primary key
• Data is ordered
• Can have secondary indexes
• Useful for tables that are fully accessed
• Overflow for less-used data
COMPOSITE INDEXES
• Sometimes known as covering or concatenated
• Consist of more than one column
• Leading column is important
COMPOSITE INDEXES
create index test_i1 on test(col1);
create index test_i2 on test(col1, col2);
COMPOSITE INDEXES
• Choosing a leading column
• High cardinality?
• Low cardinality?
• Most frequently accessed
• The Poor-Man’s IOT
•Use to improve performance of select by reducing I/O
COVERING INDEXES
SELECT price_id, price FROM dcs_price WHERE version_id = :1 AND price_id = :2;
-------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 29 | 5 (0)| 00:00:01 ||* 1 | TABLE ACCESS BY INDEX ROWID| DCS_PRICE | 1 | 29 | 5 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | DCS_PRICE_P | 2 | | 3 (0)| 00:00:01 |-------------------------------------------------------------------------------------------
create unique index dcs_price_i3 on dcs_price ( price_id, version_id, price);
-----------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 22 | 2 (0)| 00:00:01 ||* 1 | INDEX RANGE SCAN| DCS_PRICE_I03 | 1 | 22 | 2 (0)| 00:00:01 |-----------------------------------------------------------------------------------
COMPRESSED KEY INDEXES
• Leading columns have low cardinality
• Save space
• Improve performance
BITMAP INDEXES
• Index on low cardinality data
• Take up little space
• Bitmap join
• Typically found in data warehouse environments
FUNCTION BASED, INDEXED VIRTUAL
• Index on a database function (predefined, user written)
• Allows index lookups when a function is used
• Both store the derived value in the index
INVISIBLE INDEXES
• Create or modify an index to be invisible
• Invisible to the optimizer
• Still maintained by the database
• Better, more reliable option than MONITORING USAGE
• Must set optimizer_use_invisible_indexes=TRUE
VIRTUAL INDEXES
• Only visible to the optimizer
• Used for evaluating an indexes usefulness
VIRTUAL INDEXES
SQL> create table test (col1 integer);Table created.
SQL> create index test_i1 on test(col1);Index created.
SQL> create index test_i2 on test(col1);create index test_i2 on test(col1) *ERROR at line 1:ORA-01408: such column list already indexed
VIRTUAL INDEXES
SQL> create index test_i2 on test(col1) nosegment;
Index created.
SQL> select table_name, index_name, column_name from user_ind_columns where table_name = 'TEST';
TABLE_NAME INDEX_NAME COLUMN_NAME------------------------------ ------------------------------ --------------------TEST TEST_I1 COL1TEST TEST_I2 COL1
CLUSTER INDEXES
• B-Tree Cluster Index
• Hash Cluster Index
• Hash clusters can exist on a single table
PARTITIONED INDEXES
• Global Partitioned
• Crosses partitions
• Exists on whole table
• Local Partitioned
• Unique to each partition
• Watch out for non-partitioned indexes on partitions
PARTITIONED INDEXES
• Locally partitioned indexes
• Isolate maintenance operations to a single partition• Mark unusable/invisible independently• Separate partitions into different tablespaces• Prefixed, non-prefixed• Unique indexes must include partition key• Can only exist on partitioned tables
PARTITIONED INDEXES
• Globally partitioned indexes
• Can exist on non-partitioned tables
• Can be either range or hash based
• Partition maintenance can render the index unusable
• Global indexes on partitioned tables must lead with the partition key
PARTITIONED INDEXES
Local partitionPartition index unusablePartition index unusablePartitions involved unusablePartition index unusableNo effect on indexNo effect on index
Global or non-partitionEntire index unusableEntire index unusableEntire index unusableEntire index unusableEntire index unusableEntire index unusable
OperationSplitMoveMergeExchangeTruncateDrop
WHAT TO INDEX
• Primary keys
• Unique keys
• Foreign keys
• Columns frequently used in where, distinct, and order by clauses
• Columns often queried together
Index all that should be, and no more.
If in doubt, b-tree is probably safest.
KEY CONSIDERATIONS
Create primary and unique keys within a create table or build the indexes and constraints separately?
The create table method is easier, but:
• Indexes don’t persist
• May break GoldenGate, replication
create table test1 ( col1 integer);
create unique index test1_p on test1(col1);
alter table test1 add constraint test1_p primary key (col1) using index test1_p;
create table test2 ( col1 integer primary key);
-or-
create table test2 ( col1 integer, constraint test2_p primary key (col1));
select table_name, index_name from dba_indexes where table_name like 'TEST%';
TEST2 SYS_C0015135TEST1 TEST1_P
alter table test1 drop constraint test1_p; alter table test2 drop constraint SYS_C0015135;
select table_name, index_name from dba_indexes where table_name like 'TEST%';
TEST1 TEST1_P
• Pick a convention and stick to it!
•tablename_p•tablename_un•tablename_in•tablename_fn•tablename_bn• ...etc
NAMING CONVENTION
--------------------------------------------------------------------------------------------------------| Id | Operation" " " "" " " | Name" " " | Rows | Bytes| Cost (%CPU)| Time " |--------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT"" "" " " |" " " " | 30| 4230| 560 (1)| 00:00:07|| 1 | SORT ORDER BY" " " "" " |" " " " | 30| 4230| 560 (1)| 00:00:07|| 2 | NESTED LOOPS" " " "" " |" " " " | 30| 4230| 559 (1)| 00:00:07|| 3 | NESTED LOOPS "" "" " " |" " " " | 30| 3630| 552 (1)| 00:00:07|| 4 | NESTED LOOPS"" "" " " |" " " " | 30| 2790| 544 (1)| 00:00:07|| 5 | MERGE JOIN "" "" " " |" " " " | 30| 1290| 537 (1)| 00:00:07||* 6 | TABLE ACCESS BY INDEX ROWID " | TICKET_STATUSES" | 7| 42| 1 (0)| 00:00:01||* 7 | INDEX FULL SCAN" " "" | SYS_C0107546 | 10| | 1 (0)| 00:00:01||* 8 | SORT JOIN "" "" " " |" " " " | 35| 1295| 536 (1)| 00:00:07||* 9 | TABLE ACCESS BY INDEX ROWID " | TICKETS"" " | 35| 1295| 535 (1)| 00:00:07|| 10 | " BITMAP CONVERSION TO ROWIDS " " |" " " " | | |" " |" " || 11 | " BITMAP AND" " "" " " |" " " " | | |" " " |" " || 12 | " BITMAP MINUS" " "" " |" " " " | | |" " | " " ||* 13 | " BITMAP INDEX SINGLE VALUE" " | TICKETS1 " | | |" " | " " ||* 14 | " BITMAP INDEX SINGLE VALUE" " | IDX_TICKETS_I01 " | | |" " " | " " ||* 15 | " BITMAP INDEX SINGLE VALUE " " | TICKETS_INDEX | | |" " " |" " || 16 | TABLE ACCESS BY INDEX ROWID " | PANELS"" " | 1| 50| 1 (0)| 00:00:01||* 17 | INDEX UNIQUE SCAN " "" " | SYS_C0367234 " | 1| | 1 (0)| 00:00:01|| 18 | TABLE ACCESS BY INDEX ROWID " | USERS" " " | 1| 28| 1 (0)| 00:00:01||* 19 | INDEX UNIQUE SCAN" " "" | SYS_C0038942" | 1| | 1 (0)| 00:00:01|| 20 | TABLE ACCESS BY INDEX ROWID" "" | CUSTOMERS " " | 1| 20| 1 (0)| 00:00:01||* 21 | INDEX UNIQUE SCAN"" "" " | SYS_C8712300" | 1| | 1 (0)| 00:00:01|--------------------------------------------------------------------------------------------------------
STORAGE
• Consider separating table and index tablespaces
• Specify suitable storage parameters
• PCTFREE is meaningless in indexes
•logging/nologging
• Extent and block size can be defined
• Manage backups
• Manage physical storage
• Index reorganization options
•alter index rebuild
•alter index coalesce
•alter index shrink space (compact)
MAINTENANCE
• Use DBMS_STATS
• Defaults are usually best: exec dbms_stats.set_global_prefs(‘METHOD_OPT’, ‘FOR ALL COLUMNS SIZE AUTO’);exec dbms_stats.reset_global_pref_defaults;
•CASCADE=TRUE
structureddata.org/2008/10/14/dbms_stats-method_opt-and-for-all-indexed-columns/
GENERATING STATISTICS
• Introduced in 11g
• Allows you to create column groups
• Determines a relationship among potentially skewed data
dbms_stats.create_extended_stats(‘APP’, ‘CUSTOMERS’, ‘(BIRTHDATE, BIRTHSTONE)’);
EXTENDED STATISTICS
[email protected]@bodybuilding.com
gi thub.com/orac lesean/or ac le